Using PHPUnit

×

Installation Directories and Software Versions

  • PHP was used from our XAMPP installation at: d:\xampp\php;
  • PHPUnit Installation Direcotory: D:\PHP\phpunit;
  • Windows 7
  • NetBeans 8.2
  • PHP 5.5.15
  • PHPUnit 4.8.36
  • phpunit-skelgen-1.2.1.

Install PHPUnit on Windows7

Verify your PHP version from your XAMPP install on Windows

D:\PHP\phpunit>  d:\xampp\php\php.exe --version
PHP 5.5.15 (cli) (built: Jul 23 2014 15:05:09)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    with Xdebug v2.2.3, Copyright (c) 2002-2013, by Derick Rethans

Download PHPUnit and phpunit-skelgen package

Packages selected for download based on my PHP 5.5.15 version

  • phpunit-4.8.36.phar
  • phpunit-skelgen-1.2.1.phar
  • Directory location for PHPUnit files: D:\PHP\phpunit

Rename/Copy files

  • phpunit-4.8.36.phar -> phpunit.phar
  • phpunit-skelgen-1.2.1.phar -> phpunit-skelgen.phar

Create a new PHPUnit Command File

  • D:\PHP\phpunit> echo @php “%~dp0phpunit.phar” %* > phpunit.cmd

Modify your Windows Path varaible and verify your installation

Add to your windows PATH:   D:\PHP\phpunit;d:\xampp\php; ....

Finally verify the PHPUnit installation 
D:\Users\helmut> phpunit --version
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.

Run a PHPUnit Sample from the Command Line

Directory structure matches Netbeans Project structure

 * Directory structure:
 * ├── PhpUnitTest
 *         ├── Calculator.php
 *         ├── tests
 *               ├── bootstrap.php
 *               ├── CalculatorTest.php

Calculator.php our PHP test class

class Calculator
{
    /**
     * @assert (0, 0) == 0
     * @assert (0, 1) == 1
     * @assert (1, 0) == 1
     * @assert (1, 1) == 2
     * @assert (1, 2) == 4
     */
    public function add($a, $b)
    {
        return $a + $b;
    }
}

bootstrap.php our PHP class to autoload PHP classes for testing

chdir("..");                // Note our tests directory is located just below our real PHP files  
echo "Current Working Directory:: " . getcwd() . "\n";
class Autoloader{
    public static function register(){
        //echo "Inside Register ..\n";
        spl_autoload_register(function ($class) {
            $file = str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
            if (file_exists($file)) {
                require $file;
                echo "+++ Autoload of PHP File:: " . $file . "\n";
                return true;
            }
            return false;
        });
    }
}
Autoloader::register();

Create the test class using phpunit-skelgen.phar

D:\xampp\htdocs\tc\PhpUnitTest> php \php\phpunit\phpunit-skelgen.phar --test Calculator
PHPUnit Skeleton Generator 1.2.1 by Sebastian Bergmann.
Wrote skeleton for "CalculatorTest" to "D:\xampp\htdocs\tc\PhpUnitTest\CalculatorTest.php".

Copy CalculatorTest.php  to the tests directory 
D:\xampp\htdocs\tc\PhpUnitTest> copy CalculatorTest.php tests
tests\CalculatorTest.php überschreiben? (Ja/Nein/Alle): ja

Test class generated by phpunit-skelgen.phar

/**
 * Generated by PHPUnit_SkeletonGenerator 1.2.1 on 2018-03-04 at 12:37:11.
 */
class CalculatorTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var Calculator
     */
    protected $object;

    /**
     * Sets up the fixture, for example, opens a network connection.
     * This method is called before a test is executed.
     */
    protected function setUp()
    {
        $this->object = new Calculator;
    }

    /**
     * Tears down the fixture, for example, closes a network connection.
     * This method is called after a test is executed.
     */
    protected function tearDown()
    {
    }

    /**
     * Generated from @assert (0, 0) == 0.
     *
     * @covers Calculator::add
     */
    public function testAdd()
    {
        $this->assertEquals(
          0,
          $this->object->add(0, 0)
        );
    }

    /**
     * Generated from @assert (0, 1) == 1.
     *
     * @covers Calculator::add
     */
    public function testAdd2()
    {
        $this->assertEquals(
          1,
          $this->object->add(0, 1)
        );
    }

    /**
     * Generated from @assert (1, 0) == 1.
     *
     * @covers Calculator::add
     */
    public function testAdd3()
    {
        $this->assertEquals(
          1,
          $this->object->add(1, 0)
        );
    }

    /**
     * Generated from @assert (1, 1) == 2.
     *
     * @covers Calculator::add
     */
    public function testAdd4()
    {
        $this->assertEquals(
          2,
          $this->object->add(1, 1)
        );
    }

    /**
     * Generated from @assert (1, 2) == 4.
     *
     * @covers Calculator::add
     */
    public function testAdd5()
    {
        $this->assertEquals(
          4,
          $this->object->add(1, 2)
        );
    }
}

Run the php Unit test

D:\xampp\htdocs\tc\PhpUnitTest\tests> phpunit --bootstrap bootstrap.php CalculatorTest.php 
Current Working Directory:: D:\xampp\htdocs\tc\PhpUnitTest
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.

.
+++ Autoload of PHP File:: Calculator.php
...F

Time: 237 ms, Memory: 9.50MB

There was 1 failure:

1) CalculatorTest::testAdd5
Failed asserting that 3 matches expected 4.

D:\xampp\htdocs\tc\PhpUnitTest\tests\CalculatorTest.php:91

FAILURES!
Tests: 5, Assertions: 5, Failures: 1.

Return Codes from phpUnit

* PHPUnit Return Codes:   
 * .   Printed when the test succeeds.
 * F   Printed when an assertion fails while running the test method.
 * E   Printed when an error occurs while running the test method.
 * R   Printed when the test has been marked as risky (see Chapter 6).
 * S   Printed when the test has been skipped (see Chapter 7).
 * I   Printed when the test is marked as being incomplete or not yet implemented (see Chapter 7).      

PHPUnit and Netbeans Integration

Generic setup for PHPUnit within NetBeans IDE

Tools -> Option -> PHP -> PHP Framework -> PHPUnit
Image phpunit_img1.jpg  NOT Found

Create a new PHP project with the above Source for calcualater.php

Setup PHPUnit as test Provider

Right Click Project [ PhpUnitTest3] -> Properties -> Testing -> Add Folder
Image phpunit_img2.jpg  NOT Found

Create the PHP Test Classes

Right Click on Calculator.php -> Tools -> Create/Update Tests
Image phpunit_img3.jpg  NOT Found
 
Netbeans should create  CalculatorTest.php in out tests directory by running: 
"D:\xampp\php\php.exe" "D:\PHP\phpunit\phpunit-skelgen.phar" "--test" "--" "Calculator" 
    "D:\xampp\htdocs\PhpUnitTest3\Calculator.php" "CalculatorTest" "D:\xampp\htdocs\PhpUnitTest3\tests\CalculatorTest.php"
PHPUnit Skeleton Generator 1.2.1 by Sebastian Bergmann.

Wrote skeleton for "CalculatorTest" to "D:\xampp\htdocs\PhpUnitTest3\tests\CalculatorTest.php".  

Copy above bootstrap.php to our test folder and modify PHPUnit settings

Right Click Project [ PhpUnitTest3] -> Properties -> PHPUnit
Image phpunit_img4.jpg  NOT Found
Project Files and Directories sould now look like: 
* Directory structure:
 * ├── PhpUnitTest
 *         ├── Calculator.php
 *         ├── tests
 *               ├── bootstrap.php
 *               ├── CalculatorTest.php

Finally run PHPUnit tests

Right Click Calculator.php -> Test
Image phpunit_img5.jpg  NOT Found

PHP and Reference Operator &

Overview

  • Scalars are passed by values
  • To pass Scalars by reference you need to use the & Reference Operator
  • Objects are passed by Reference

PHP sample Code


class WRLoginObj {
    public $pvName = "";
    public $isOnline = false;
    
    function  __construct($pvName, $isOnline ) {
        $this->pvName = $pvName;
        $this->isOnline = $isOnline;
        }
}

$wrLoginObjArr = [];
initApp();
function initApp() {
	$isOnline = "false";
	$wrLoginObjArr = [];
	$wrLoginObj = new WRLoginObj("PV1", "false"  );
    array_push( $wrLoginObjArr, $wrLoginObj );
    $wrLoginObj = new WRLoginObj("PV2", "false"  );
    array_push( $wrLoginObjArr, $wrLoginObj );
    
    echo("Object Test: Objects/Arrays are passed by reference\n");
    dumpObjData($wrLoginObjArr);
    changeObjData($wrLoginObjArr);
    dumpObjData($wrLoginObjArr);
    
    echo("Scalar before changeSclar() [ Original Value ] - isOnline:  " .$isOnline . "\n"  );
    changeSclarCopyByWrite($isOnline);
    echo("Scalar after changeSclarCopyByWrite [ Nothing changed ]  - isOnline:  " .$isOnline . "\n" );
    changeScalarbyRef($isOnline);
    echo("Scalar after changeScalarByRef() [ Changed value ] - isOnline:  " .$isOnline . "\n" );
}        

function changeScalarByRef(&$val) {
	$val = "true";
}

function changeSclarCopyByWrite($val) {
	$val = "true";
}

function dumpObjData($loginArr) {
	foreach ($loginArr as $loginObj) {
		echo ("pvName: " . $loginObj->pvName . "  - Status:  ". $loginObj->isOnline . "\n") ;
	}
}	

function changeObjData($loginArr) {
	foreach ($loginArr as $loginObj) {
		$loginObj->isOnline = "true";
	}
}

PHP Program Output

D:\xampp\htdocs\tc>  php objRef.php 
Object Test: Objects/Arrays are passed by reference
pvName: PV1  - Status:  false
pvName: PV2  - Status:  false
pvName: PV1  - Status:  true
pvName: PV2  - Status:  true
Scalar before changeSclar() [ Original Value ] - isOnline:  false
Scalar after changeSclarCopyByWrite [ Nothing changed ]  - isOnline:  false
Scalar after changeScalarByRef() [ Changed value ] - isOnline:  true

PHP Static Class

PHP Static Class

Overview

  • A static PHP class is a specific implementation of the Singelton Design Pattern.
  • A static class variable can be accessed without instantiating the class first
  • This also means that there will only be one version of this variable.
  • A static method cannot access non-static variables and methods, since these require an instance of the class.
  • To access our static variable from our static class method, we prefix it with the self keyword ( works only inside the class )
  • From outside the class, we use the name of the class with double-colon operator

Code Sample

class PHPLogger{  
    public static  $loggerName = "Helmut's PHP-Logger:: ";
    public static $loggerLogLevel = 3;
    
    public static function getLogLevel() { return self::$loggerLogLevel; }
    public static function setLogLevel($level) { 
        self::$loggerLogLevel = $level; 
        echo self::$loggerName."Set New Logger Loglevel to: ". self::$loggerLogLevel."\n";
    }
}    
echo PHPLogger::$loggerName."Initial LogLevel: ". PHPLogger::getLogLevel() ."\n";
PHPLogger::setLogLevel(2);
echo PHPLogger::$loggerName."New LogLevel: " . PHPLogger::getLogLevel()."\n";

Code Output

D:\xampp\htdocs\pvdata\wrapp\public_html\php> php logger.php

Helmut's PHP-Logger:: Initial LogLevel: 3
Helmut's PHP-Logger:: Set New Logger Loglevel to: 2
Helmut's PHP-Logger:: New LogLevel: 2

Reference

PHP: XML Parsing with simplexml_load_file()

  • PHP’s SimpleXML extension was introduced back in PHP 5.0
  • An increasing number of web services return data in JSON format, but a large number still return XML
  • The code below demonstrates  both reading of : XML Elements and XML Attributes
  • The entire DOM tree is read into memory and returns a SimpleXMLElement PHP object
  • Use this APi with caution for large XML files 

XML data

    <trk>
        <name>Neue Positionsliste 1</name>
        <trkseg>
            <trkpt lat="49.81208" lon="11.353953">
                <ele>379.0</ele>
                <time>2015-12-07T12:47:05.000Z</time>
                <name>Position 1</name>
                <extensions>
                    <nmea:speed>2.45</nmea:speed>
                </extensions>
            </trkpt>
            <trkpt lat="49.812103" lon="11.353962">
                <ele>379.0</ele>
                <time>2015-12-07T12:47:06.000Z</time>
                <name>Position 2</name>
                <extensions>
                    <nmea:speed>2.75</nmea:speed>
                </extensions>
            </trkpt>
      ...

PHP code

 function parseGPX($dirName, $fileName)
  {
  global $gpxArray;
  global $gpxCount;
  
  $gpxArray = simplexml_load_file($dirName.$fileName);
  $gpxCount = count($gpxArray->trk->trkseg->trkpt);
  $i = 0;
  print_r($gpxArray->trk->trkseg->trkpt[0]);
  print_r("First GPX Element:: Lat: ".$gpxArray->trk->trkseg->trkpt[0]["lat"]." - Lon: ".$gpxArray->trk->trkseg->trkpt[0]["lon"]. 
           " - Ele: ".$gpxArray->trk->trkseg->trkpt[0]->ele."\n");
  printf("\n");   
  foreach ($gpxArray->trk->trkseg->trkpt as $gpxElem) 
      {
      $i++;
      if ( $i == 1 || $i == $gpxCount || ( $i % 100) === 0 )
        printf("\n% -4d: Lat: % -10s - Lon:% -10s - Ele: % -6s", $i, $gpxElem["lat"], $gpxElem["lon"], $gpxElem->ele );   
    }    
  printf("\n");   
  print_r("GPX Array Count: ".count($gpxArray->trk->trkseg->trkpt)."\n");
  error_log('gpxCount: '.$gpxCount);
  }

PHP Output

(
    [@attributes] => Array
        (
            [lat] => 49.81208
            [lon] => 11.353953
        )

    [ele] => 379.0
    [time] => 2015-12-07T12:47:05.000Z
    [name] => Position 1
    [extensions] => SimpleXMLElement Object
        (
        )

)
Output:   
First GPX Element:: Lat: 49.81208 - Lon: 11.353953 - Ele: 379.0

1   : Lat: 49.81208   - Lon:11.353953  - Ele: 379.0
100 : Lat: 49.81406   - Lon:11.353427  - Ele: 393.0
200 : Lat: 49.814999  - Lon:11.35364   - Ele: 405.0
300 : Lat: 49.815887  - Lon:11.354074  - Ele: 420.0
400 : Lat: 49.816792  - Lon:11.35475   - Ele: 409.0
500 : Lat: 49.817665  - Lon:11.355126  - Ele: 407.0
600 : Lat: 49.818573  - Lon:11.354907  - Ele: 414.0
700 : Lat: 49.819462  - Lon:11.35405   - Ele: 417.0
800 : Lat: 49.820202  - Lon:11.353247  - Ele: 417.0
900 : Lat: 49.820946  - Lon:11.35268   - Ele: 427.0
1000: Lat: 49.821693  - Lon:11.352285  - Ele: 438.0
1100: Lat: 49.822273  - Lon:11.353273  - Ele: 441.0
1200: Lat: 49.823071  - Lon:11.353742  - Ele: 448.0
1222: Lat: 49.823299  - Lon:11.353806  - Ele: 448.0
GPX Array Count: 1222  

Reference

PHP: Pass an Array to Javascript using AJAX (jquery ) and PHP’s json_encode

PHP Code to build an Array of Arrays

    
    ....
    $container_arr = array();
    $arr = array(
        'src' =>  get_stylesheet_directory().'/images/track1/i3.jpg',
          'log'  => 'Array1:: '.$PHPBufferX,
        'warn'  => $PHPwarnX,
        'error' => $PHPerrorX
          );
  array_push(  $container_arr, (array)$arr );
  
  $arr = array(
        'src' =>  get_stylesheet_directory().'/images/track1/i4.jpg',
          'log'  => 'Array2:: '.$PHPBufferX,
        'warn'  => $PHPwarnX,
        'error' => $PHPerrorX
          ); 
  array_push(  $container_arr,  (array)$arr );
          
  echo json_encode($container_arr);
  error_log('JSON ENCODE ok ...');  
  die();

JavaScript / JQuery Code to read Arrays

jQuery(document).ready(function()
{
var greeting = jQuery("#greeting3").val();
var trackids = jQuery("#trackids").val();
jQuery("#ajax3-button").click(function()
{
console.log('ajax3-button pressed') ;
jQuery.ajax({
type: 'POST',
url :  'http://localhost/wordpress/wp-admin/admin-ajax.php',
data: { action: 'myAjax2', greeting3: greeting, trackids: trackids   },
// dataType: 'html',  /* used for JSON Debugging */
dataType: 'json',
success: function(data, textStatus, XMLHttpRequest)
{
console.log("Returing from AJAX request - Adding greetings to Div:  #divp4 ");

   $.each(data, function(index, obj)
    {
    jQuery("#divp4").append('<p><b>Array Index: '+ (index+1) + '</p>');
    jQuery("#divp4").append('<p><b>Image SRC  : </b>' + obj.src +'</p>');
    jQuery("#divp4").append('<p><b>PHP LOG    : </b>' + obj.log +'</p>');
    jQuery("#divp4").append('<p><b>Warnings   : </b>' + obj.warn +'</p>');
    jQuery("#divp4").append('<p><b>Errors     : </b>' + data.error +'</p>');
    });
   //      jQuery("#divp4").append('<p>'+ data + '</p>');   /* used for JSON Debugging */
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{ alert(errorThrown); }
});
var ih = '<p>AJAX3 button presesed : AJAX request in progress ! - Trackids: ' + trackids +' </p>' ;
document.getElementById("divp3").innerHTML = ih;
console.log('Leaving ajax3-button Ajax action');
});
});

Output:

 
Array Index: 1
Image SRC : D:\xampp\htdocs\wordpress/wp-content/themes/twentyfifteen-child/images/track1/i3.jpg
PHP LOG : Array1:: Greeting from AJAX request 3:: - CWD: : D:\xampp\htdocs\wordpress\wp-admin
Warnings : null
Errors : undefined

Array Index: 2
Image SRC : D:\xampp\htdocs\wordpress/wp-content/themes/twentyfifteen-child/images/track1/i4.jpg
PHP LOG : Array2:: Greeting from AJAX request 3:: - CWD: : D:\xampp\htdocs\wordpress\wp-admin
Warnings : null
Errors : undefined

 PHP Error Log

  • The array output was triggered by a print_r  PHP comand
  • The Output was deleted by running ob_end_clean() before running:  echo json_encode($container_arr);
[04-Dec-2015 16:09:39 UTC] myAjax2()
[04-Dec-2015 16:09:39 UTC] ajaxWrapper():: ob_start with CallBack Function
[04-Dec-2015 16:09:39 UTC] PHP Parse DUMP::
[04-Dec-2015 16:09:39 UTC] JSON ENCODE  ...
[04-Dec-2015 16:09:39 UTC] myObCallback() active ::  Cleaning Current PHP Buffer:: 
Array
(
    [0] => Array
        (
            [src] => D:\xampp\htdocs\wordpress/wp-content/themes/twentyfifteen-child/images/track1/i3.jpg
            [log] => Array1:: Greeting from AJAX request 3::  - CWD: D:\xampp\htdocs\wordpress\wp-admin</
            [warn] =>
            [error] =>
        )
    [1] => Array
        (
            [src] => D:\xampp\htdocs\wordpress/wp-content/themes/twentyfifteen-child/images/track1/i4.jpg
            [log] => Array2:: Greeting from AJAX request 3::  - CWD: : D:\xampp\htdocs\wordpress\wp-admin</
            [warn] =>
            [error] =>
        )

)
[04-Dec-2015 16:09:39 UTC] JSON ENCODE ok - Now Dying ...
[04-Dec-2015 16:09:39 UTC]  -------------- [SHUTDOWNHANDLER]:: Start  -----------------------
[04-Dec-2015 16:09:39 UTC] [logLastError]:: No errors/Warnings found in this PHP Page
[04-Dec-2015 16:09:39 UTC]  -------------- [xx SHUTDOWNHANDLER]:: Leaving:  -----------------------

Reference

 

Handling PHP Parse Errors

Typical PHP Script errors and their default Action

In the following POST we will have a closer look at the following PHP Script Errors 

 Value     Constant     Description
     1     E_ERROR     Fatal run-time errors. Errors that cannot be recovered from. Execution of the script is halted        
     4     E_PARSE     Compile-time parse errors. Parse errors should only be generated by the parser. Script is halted.
     8     E_NOTICE    Run-time notices. The script found something that might be an error, but could also happen when 
                       running a script normaly . Script runs to the END.

Is using set_error_handler() a working solution ?

  • The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING,E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.
  • Using set_error_handler is only useful for debugging Warnings [ like uninitialised variables ]
  • If using a user function (error_handler) to handle errors in a script by using set_error_handler() any WARNING  will not get displayed in our register_shutdown_function() at the PHP page end.  This is not expected !
  • As set_error_handler() can’t be used for all errors  we should use register_shutdown_function instead

 

Using register_shutdown_function() to handle PARSE, RUNTIME and WARNINGS

  • Parse Errors can only be handled by using  register_shutdown_function in the top level PHP Page
  • PHP shutdownhandler() uses  error_get_last() to retrieve the latest PHP error/warning
  • NOTE: YOU should disable any error handler ( set by set_error_handler() ) if you want to log even WARNING messages.

PHP Code for our TOP LEVEL Page

 
<?php

include 'phpErrorHandler.php';                   /* defines errorHandler and shutdownHandler function */
// set_error_handler("errorHandler");            /* disable _error_handler when using register_shutdown_function */
                                                 /* If  set_error_handler() is enabled WARNIGNS will be missed in our  registered shutdown function*/
register_shutdown_function("shutdownHandler");
ini_set('display_errors', false);               /* Note PHP errors may break the JSON traffic in our AJAX requests */ 
                                                /* Don't to display any Errors in the Browser Window  */ 
ini_set('error_reporting', E_ALL); 
$handlerType='TOP LEVEL';  
  
echo "<p>____Before Error::</p>";
include 'create_a_php_error.php';                /* The PHP source with an errors */
      /* Note we will never reach this line in case of syntax errors in create_a_php_error.php  */
echo "<p>____After Include:: </p>"; 
runme();                                         /* The function with an error */
echo "<p>____Leaving Page:: </p>";
?>   

PHP Code for our shutdownHandler

 
<?php

function shutdownHandler()   //will be called when php script ends.
{
   global $handlerType;
   logError(" -------------- Inside shutdownHandler: ".$handlerType." -----------------------", "info"); 
   $lasterror = error_get_last();
   if ( $lasterror ===  null )
        logError('[SHUTDOWNHANDLER]:: No errors found in PHP Page',"info");
   else
     {
           // logError('[SHUTDOWNHANDLER]:: Found errors found in PHP Page: - Error Type::  '.$lasterror['type'] ,"info");       
      switch ($lasterror['type'])
       {
            case E_ERROR:
              case E_CORE_ERROR:
              case E_COMPILE_ERROR:
              case E_USER_ERROR:
              case E_RECOVERABLE_ERROR:
              case E_CORE_WARNING:
              case E_COMPILE_WARNING:
              case E_PARSE:    
                {   
                $error = "[SHUTDOWNHANDLER] lvl:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line'];
                      //  echo '<p><b>'.$error.'</b></p>';
                logError($error, "fatal");
                break;
                }
              default:
                {
                $error = "[SHUTDOWNHANDLER: Unknown Type ] LVL:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line'];
                  logError($error, "fatal"); 
                  }
          }
    }
}

function logError($error, $errlvl)
{
  error_log($error);                /* Write to PHP error log */ 
  echo '<p><b>'.$error.'<b></p>';   /* Display the error in our PHP page */
}

?>

PHP Code to be tested –  Runtime Warningthrows E_NOTICE error

 
<?php 
  function runme()
      {
      global $handlerType;
      $handlerType ='2nd LEVEL';     
      echo "<p><b>function runme():: This function creates a PHP Warning , PHP Runtime Error or PHP Syntax Error ! </b></p>";
    
    /* Error1 : Runtime Warning - throws E_NOTICE error */ 
    echo $test;
      
      echo "<p>Leaving function runme - Now dying !</p>";
      die();
    }
?>

HTML Output:     
____Before Error::
____After Include::
function runme():: This function creates a PHP Warning , PHP Runtime Error or PHP Syntax Error !
Leaving function runme - Now dying !
-------------- Inside shutdownHandler: 2nd LEVEL -----------------------
[SHUTDOWNHANDLER: Unknown Type ] LVL:8 | msg:Undefined variable: test | file:D:\xampp\htdocs\create_a_php_error.php | ln:23

PHP Log :
[29-Nov-2015 18:16:31 Europe/Berlin] PHP Notice:  Undefined variable: test in D:\xampp\htdocs\create_a_php_error.php on line 23
[29-Nov-2015 18:16:31 Europe/Berlin]  -------------- Inside shutdownHandler: 2nd LEVEL -----------------------
[29-Nov-2015 18:16:31 Europe/Berlin] [SHUTDOWNHANDLER: Unknown Type ] LVL:8 | msg:Undefined variable: test | 
                                     file:D:\xampp\htdocs\create_a_php_error.php | ln:23
  • As we get only  E_NOTICE Warning  the script runs to the end
  • Our PAGE SHUTDOWNHANDLER is able to retrieve  this WARNING

PHP Code to be tested –  Fatal Runtime error :  E_ERROR

 
<?php  
  function runme()
      {
      global $handlerType;
      $handlerType ='2nd LEVEL';     
      echo "<p><b>function runme():: This function creates a PHP Warning , PHP Runtime Error or PHP Syntax Error ! </b></p>";
    
    /* Error2 : Runtime Error - throws E_ERROR */
     echo "<p>Curent Working directory: ".getcd() . "</p>";   
  
      echo "<p>Leaving function runme - Now dying !</p>";
      die();
    }
?>

HTML Output:
____Before Error::
____After Include::
function runme():: This function creates a PHP Warning , PHP Runtime Error or PHP Syntax Error !
-------------- Inside shutdownHandler: 2nd LEVEL -----------------------
[SHUTDOWNHANDLER] lvl:1 | msg:Call to undefined function getcd() | file:D:\xampp\htdocs\create_a_php_error.php | ln:26   

PHP Error LOG:
[29-Nov-2015 18:24:09 Europe/Berlin] PHP Fatal error:  Call to undefined function getcd() in 
                                      D:\xampp\htdocs\create_a_php_error.php on line 26
[29-Nov-2015 18:24:09 Europe/Berlin]  -------------- Inside shutdownHandler: 2nd LEVEL -----------------------
[29-Nov-2015 18:24:09 Europe/Berlin] [SHUTDOWNHANDLER] lvl:1 | msg:Call to undefined function getcd() | 
                                     file:D:\xampp\htdocs\create_a_php_error.php | ln:26
  • Note this script was aborted due to fatal E_ERROR error

PHP Code to be tested –  Fatal PARSE error :  E_PARSE

 
<?php  
  function runme()
      {
      global $handlerType;
      $handlerType ='2nd LEVEL';     
      echo "<p><b>function runme():: This function creates a PHP Warning , PHP Runtime Error or PHP Syntax Error ! </b></p>";
    
      /* Error 3: Syntax error -  throws E_PARSE : this is a fatal error an can only handled in the TOP level PHP page  */
      logS(    
      
      echo "<p>Leaving function runme - Now dying !</p>";
      die();
    }
?>

HTML Output:
____Before Error::
-------------- Inside shutdownHandler: TOP LEVEL -----------------------
[SHUTDOWNHANDLER] lvl:4 | msg:syntax error, unexpected 'echo' (T_ECHO) | file:D:\xampp\htdocs\create_a_php_error.php | ln:31

PHP Error LOG:
[29-Nov-2015 18:31:07 Europe/Berlin] PHP Parse error:  syntax error, unexpected 'echo' (T_ECHO) in 
                                     D:\xampp\htdocs\create_a_php_error.php on line 31
[29-Nov-2015 18:31:07 Europe/Berlin]  -------------- Inside shutdownHandler: TOP LEVEL -----------------------
[29-Nov-2015 18:31:07 Europe/Berlin] [SHUTDOWNHANDLER] lvl:4 | msg:syntax error, unexpected 'echo' (T_ECHO) | 
                                     file:D:\xampp\htdocs\create_a_php_error.php | ln:31
  • Note this script was aborted due to fatal E_PARSE error
  • Only if we have registered a SHUTDOWNHANDLER in our top level page we can catch this type of PARSE errors

Reference