CategoryPHP

Ando_ErrorFactory

I’ve added a new class to my framework, Ando_ErrorFactory.

Here I use it to make PHP trigger an E_CORE_ERROR:

<?php

echo "\n-- s t a r t --\n";

error_reporting(E_ALL | E_STRICT);
require dirname(__FILE__) . '/../vendor/Ando/ErrorFactory.php';
Ando_ErrorFactory::register_non_shutdown_error_visualizer();
Ando_ErrorFactory::register_shutdown_error_visualizer();

//Ando_ErrorFactory::E_ERROR();
//Ando_ErrorFactory::E_WARNING();
//Ando_ErrorFactory::E_NOTICE();
//Ando_ErrorFactory::E_PARSE();
Ando_ErrorFactory::E_CORE_ERROR();
////Ando_ErrorFactory::E_CORE_WARNING();
//Ando_ErrorFactory::E_COMPILE_ERROR();
//Ando_ErrorFactory::E_COMPILE_WARNING();
//Ando_ErrorFactory::E_USER_ERROR();
//Ando_ErrorFactory::E_USER_WARNING();
//Ando_ErrorFactory::E_USER_NOTICE();
//Ando_ErrorFactory::E_STRICT();
//Ando_ErrorFactory::E_RECOVERABLE_ERROR();
//Ando_ErrorFactory::E_DEPRECATED();
//Ando_ErrorFactory::E_USER_DEPRECATED();

echo "\n-- e n d --\n";

-- s t a r t --
PHP Fatal error:  Class Oops must implement interface Traversable as part of either Iterator or IteratorAggregate in Unknown on line 0
PHP Stack trace:
PHP   1. {main}() /.../test1.php:0
PHP   2. Ando_ErrorFactory::E_CORE_ERROR() /.../test1.php:14
PHP   3. Ando_ErrorFactory->E_CORE_ERROR_by_declaring_a_class_directly_implementing_Traversable() /.../vendor/Ando/ErrorFactory.php:227
PHP   4. eval() /.../vendor/Ando/ErrorFactory.php:444

shutdown_error: E_CORE_ERROR (Fatal error)

error = Array
(
    [type] => 16
    [message] => Class Oops must implement interface Traversable as part of either Iterator or IteratorAggregate
    [file] => Unknown
    [line] => 0
)

Notice that the lines starting with “PHP” belong to STDERR (redirected to STDOUT, controlled by the ´error_reporting´ call), while the rest belong to the real STDOUT.

The take away is that we forcefully triggered an E_CORE_ERROR (fact confirmed by the STDERR portion) and our shutdown handler was able to log it (fact confirmed by the STDOUT portion). Given that such an error is a non catchable shutdown error, there is no other way to get a look at it than from inside a shutdown handler.

Here is what happens when instead we forcefully trigger an E_RECOVERABLE_ERROR:

-- s t a r t --

non_shutdown_error: E_RECOVERABLE_ERROR (Catchable fatal error)

error = Array
(
    [type] => 4096
    [message] => Object of class stdClass could not be converted to string
    [file] => /.../vendor/Ando/ErrorFactory.php(510) : eval()'d code
    [line] => 1
    [context] => Array
        (
            [code] => echo new stdClass();
        )

)

#0  Ando_ErrorFactory::non_shutdown_error(4096, Object of class stdClass could not be converted to string, /.../vendor/Ando/ErrorFactory.php(510) : eval()'d code, 1, Array ([code] => echo new stdClass();)) called at [/.../vendor/Ando/ErrorFactory.php(510) : eval()'d code:1]
#1  eval() called at [/.../vendor/Ando/ErrorFactory.php:510]
#2  Ando_ErrorFactory->E_RECOVERABLE_ERROR_by_converting_to_string_an_object_of_a_class_without__to_string() called at [/.../vendor/Ando/ErrorFactory.php:294]
#3  Ando_ErrorFactory::E_RECOVERABLE_ERROR() called at [/.../tests/tmp2.php:22]

-- e n d --

shutdown_error: (none) (Unknown error)

The presence of the ´– e n d –´ line in the output confirms, as expected, that E_RECOVERABLE_ERROR is not a shutdown error. Thanks to that, we had a chance to get to the backtrace from our non shutdown error handler, while the STDERR didn’t get written to because we signaled to PHP we successfully handled the error by returning ´true´. In fact, here is what would happen if we returned ´false´:

-- s t a r t --

non_shutdown_error: E_RECOVERABLE_ERROR (Catchable fatal error)

error = Array
(
    [type] => 4096
    [message] => Object of class stdClass could not be converted to string
    [file] => /.../vendor/Ando/ErrorFactory.php(510) : eval()'d code
    [line] => 1
    [context] => Array
        (
            [code] => echo new stdClass();
        )

)

#0  Ando_ErrorFactory::non_shutdown_error(4096, Object of class stdClass could not be converted to string, /.../vendor/Ando/ErrorFactory.php(510) : eval()'d code, 1, Array ([code] => echo new stdClass();)) called at [/.../vendor/Ando/ErrorFactory.php(510) : eval()'d code:1]
#1  eval() called at [/.../vendor/Ando/ErrorFactory.php:510]
#2  Ando_ErrorFactory->E_RECOVERABLE_ERROR_by_converting_to_string_an_object_of_a_class_without__to_string() called at [/.../vendor/Ando/ErrorFactory.php:294]
#3  Ando_ErrorFactory::E_RECOVERABLE_ERROR() called at [/.../tests/tmp2.php:22]

shutdown_error: E_RECOVERABLE_ERROR (Catchable fatal error)

error = Array
(
    [type] => 4096
    [message] => Object of class stdClass could not be converted to string
    [file] => /.../vendor/Ando/ErrorFactory.php(510) : eval()'d code
    [line] => 1
)

PHP Catchable fatal error:  Object of class stdClass could not be converted to string in /.../vendor/Ando/ErrorFactory.php(510) : eval()'d code on line 1
PHP Stack trace:
PHP   1. {main}() /.../tests/tmp2.php:0
PHP   2. Ando_ErrorFactory::E_RECOVERABLE_ERROR() /.../tests/tmp2.php:22
PHP   3. Ando_ErrorFactory->E_RECOVERABLE_ERROR_by_converting_to_string_an_object_of_a_class_without__to_string() /.../vendor/Ando/ErrorFactory.php:294
PHP   4. eval() /.../vendor/Ando/ErrorFactory.php:510

As you see, by returning ´false´, we told PHP that we didn’t successfully handle the error and to continue its default course, which in this case, being E_RECOVERABLE_ERROR a shutdown error by default, consisted in shutting down the script. As a confirmation, notice the absence of the ´– e n d –´ line in the output.

A fun fact I discovered while programming this class is that a fatal error is not necessarily a non-catchable shutdown error. In fact, both E_RECOVERABLE_ERROR and E_USER_ERROR are catchable shutdown errors. Likewise, E_PARSE, E_CORE_WARNING and E_COMPILE_WARNING are non catchable non shutdown errors. For each of these variations ErrorFactory has a corresponding method to return that set of errors.

echo 'all_errors: ',                        print_r(Ando_ErrorFactory::all_errors_to_str(), true);
echo 'catchable_errors: ',                  print_r(Ando_ErrorFactory::to_str(Ando_ErrorFactory::catchable_errors()), true);
echo 'shutdown_errors: ',                   print_r(Ando_ErrorFactory::to_str(Ando_ErrorFactory::shutdown_errors()), true);
echo 'non_catchable_errors: ',              print_r(Ando_ErrorFactory::to_str(Ando_ErrorFactory::non_catchable_errors()), true);
echo 'non_shutdown_errors: ',               print_r(Ando_ErrorFactory::to_str(Ando_ErrorFactory::non_shutdown_errors()), true);
echo 'catchable_shutdown_errors: ',         print_r(Ando_ErrorFactory::to_str(Ando_ErrorFactory::catchable_shutdown_errors()), true);
echo 'catchable_non_shutdown_errors: ',     print_r(Ando_ErrorFactory::to_str(Ando_ErrorFactory::catchable_non_shutdown_errors()), true);
echo 'non_catchable_shutdown_errors: ',     print_r(Ando_ErrorFactory::to_str(Ando_ErrorFactory::non_catchable_shutdown_errors()), true);
echo 'non_catchable_non_shutdown_errors: ', print_r(Ando_ErrorFactory::to_str(Ando_ErrorFactory::non_catchable_non_shutdown_errors()), true);

all_errors: Array
(
    [0] => E_ERROR
    [1] => E_WARNING
    [2] => E_PARSE
    [3] => E_NOTICE
    [4] => E_CORE_ERROR
    [5] => E_CORE_WARNING
    [6] => E_COMPILE_ERROR
    [7] => E_COMPILE_WARNING
    [8] => E_USER_ERROR
    [9] => E_USER_WARNING
    [10] => E_USER_NOTICE
    [11] => E_STRICT
    [12] => E_RECOVERABLE_ERROR
    [13] => E_DEPRECATED
    [14] => E_USER_DEPRECATED
)
catchable_errors: Array
(
    [0] => E_WARNING
    [1] => E_NOTICE
    [2] => E_USER_ERROR
    [3] => E_USER_WARNING
    [4] => E_USER_NOTICE
    [5] => E_STRICT
    [6] => E_RECOVERABLE_ERROR
    [7] => E_DEPRECATED
    [8] => E_USER_DEPRECATED
)
shutdown_errors: Array
(
    [0] => E_ERROR
    [1] => E_CORE_ERROR
    [2] => E_COMPILE_ERROR
    [3] => E_RECOVERABLE_ERROR
    [4] => E_USER_ERROR
)
non_catchable_errors: Array
(
    [0] => E_ERROR
    [1] => E_PARSE
    [2] => E_CORE_ERROR
    [3] => E_CORE_WARNING
    [4] => E_COMPILE_ERROR
    [5] => E_COMPILE_WARNING
)
non_shutdown_errors: Array
(
    [0] => E_WARNING
    [1] => E_PARSE
    [2] => E_NOTICE
    [3] => E_CORE_WARNING
    [4] => E_COMPILE_WARNING
    [5] => E_USER_WARNING
    [6] => E_USER_NOTICE
    [7] => E_STRICT
    [8] => E_DEPRECATED
    [9] => E_USER_DEPRECATED
)
catchable_shutdown_errors: Array
(
    [0] => E_RECOVERABLE_ERROR
    [1] => E_USER_ERROR
)
catchable_non_shutdown_errors: Array
(
    [0] => E_WARNING
    [1] => E_NOTICE
    [2] => E_USER_WARNING
    [3] => E_USER_NOTICE
    [4] => E_STRICT
    [5] => E_DEPRECATED
    [6] => E_USER_DEPRECATED
)
non_catchable_shutdown_errors: Array
(
    [0] => E_ERROR
    [1] => E_CORE_ERROR
    [2] => E_COMPILE_ERROR
)
non_catchable_non_shutdown_errors: Array
(
    [0] => E_PARSE
    [1] => E_CORE_WARNING
    [2] => E_COMPILE_WARNING
)

Note that the non_shutdown_error and shutdown_error handlers are included as a proof of concept. You are supposed to program yourself proper handlers, if and how you see fit. But you can certainly use them for testing something out, like I did above.

Unchecked property overloading is detrimental to OOP

 

Class Ando_Regex for PHP

EDIT: https://github.com/aercolino/ando-php

This is an update on my Regex class of some days ago.

{[ .class-regex | 1.hilite(=php=) ]}

Now with a bunch of tests.

{[ .tests-regex | 1.hilite(=php=) ]}

Screen Shot 2014-10-29 at 3.27.45

(previous permalink: class-regex-for-php)

Class Ando_Function for PHP

EDIT: https://github.com/aercolino/ando-php

This is a simple class for creating generic callbacks in PHP. There are a couple of reasons for using this class instead of the usual ´array( $container, $function )´ method.

First, the usual method doesn’t allow you to run the called code with more arguments than those provided by the calling code.

Second, this class resolves to the usual method when no extra arguments are provided, thus making it transparent at run time. This could seem useless, but, for free, we get much easier to spot callback calling points.

{[ .class-func | 1.hilite(=php=) ]}

Here are some tests.

{[ .tests | 1.hilite(=php=) ]}

Screen Shot 2014-10-28 at 16.53.43

(previous permalink: class-func-for-php)

Class RegularExpression for PHP

UPDATE

This is a small class for handling Regular Expressions in PHP. I often have to use backreferences and it’s very cumbersome to compose simple expressions with them into more complex ones, because I have to manually count all capturing groups many times in a row. This class basically solves that issue for me.

{[ .class | 1.hilite(=php=) ]}

 

© 2017 Notes Log

Theme by Anders NorenUp ↑