This is an old revision of the document!
Request for Comments: Enhanced Error Handling
php_error(), zend_throw_extension(), the @-operator... PHP and/or the Zend Engine respectively offer a variety of error issuance and handling mechanisms. There is, however, no encompassing concepts: Core functions only issue php_errors (suppressable), intl 1.0.3 by default suppresses all errors but can activate php_errors, pdo however has a proprietary flag to define error behaviour that allows exceptions - but limits php_error to E_WARNING.
I state that error handling has to be in the hands of the user (php coder). Some may prefer php_error()s, others prefer exceptions; some are ok with E_WARNINGs that indicate severe situations, others prefer E_ERROR for those cases; and some might want to either suppress all messages or default to a big exception block per script in production systems.
Error conditions are encountered in a variety of places and cases. This RFC only covers error conditions in a running script, e.g. a file was not found.
All other situations - like compilation problems, core errors in engine startup/shutdown - are out of scope.
If an error condition is met, different types of reactions are possible:
|Suppress||Note down error and return an error value, e.g. false/NULL|
|Error||same as Suppress, but issue a php_error as well|
|Throw||same as Suppress, but throw an exception as well|
The error behaviour should be configurable by the user; preferably system-wide and overridable. An extension should not, however, decide to differ from the user's wishes.
In any case, there should be a method to get at the noted-down error information, e.g. error code and message.
php_error needs an E_* value to distinguish warnings and errors and the Throw behaviour needs an exception class.
Defaults for those parameters should be configurable like the error behaviour. The extension should however be able, while issuing an error, to set appropriate parameters if necessary.
For extreme cases - like “one big exception block per script” - the default parameters should be enforcable by the user's wishes.
Error Container Hierarchy
PHP lives of its extensibility. An extension can offer a whole bunch of different classes
that are related; take
intl as an example. It could be interesting for the user
to differentiate his error reactions by object and/or extension.
He could wish to let the whole of
intl throw a PersonalIntlExceptionClass upon errors or
decide to switch to exceptions for a long block of translation calls (not testing each
and every result on its own) while he usually prefers E_ERRORS being issued.
The proposal therefore stands for a three-level hierarchy:
|Global||Define behaviour and default parameters|
|Could be used to force behaviour as well as parameters, eg. in production|
|Field/Extension||Inherits from Global level|
|Overrides behaviour and parameters for a “field”, e.g. all i18n in intl.so|
|Object||Inherits from Field level|
|Overrides behaviour and parameters for a single object|
If any level enforces behaviour and/or parameters, the lower levels will not deviate.
Enforced Exception class
Each level could enforce the use of a specific exception class, e.g. PersonalIntlExceptionClass() for all of intl.so. While forcing such a common class does ease catching, some information a more specific class could provide is lost.
As of PHP 5.3, the concept of exception chaining has been introduced, whereas a “previous” extension can be attached. In order to keep the previously lost information, the concrete exception class given upon issuing an error should be chained to the enforced class.
Notices are issued en masse all over PHP - even for plain language constructs like array access. They are regularly ignored on production systems and seldomly indicate errors. I like to compare them to warnings of a compiler, indicating that something could go wrong here (php does issue them at runtime, not compile-time).
Whereas an user could decide to downgrade every error to a notice in this concept, actual notices should be issued the same way as before.
The @ operator does suppress error issuance for the evaluation of the expression it is prepended to. It does so - currently - completely for php_error()s, not however for exceptions.
If possible, the operator should be limited to errors in the execution of scripts but “silence” thrown exceptions as well (like a “per object” Suppress above). It's functionality should be prohibited, if a certain behaviour is enforced.
Extensions can keep backwards compatibility, if their current default behaviour is mapped to the above-mentioned Field level. Even special cases should be representable with the mentioned behaviours, parameters and enforcement.
I would personally not touch the core, but it's error behaviour should be representable as well.
Course of Action and Patch
- An intl extension-level implementation is being created by kampfcaspar at https://saintcyr.oeri.ch/trac/php-intl/
- Given enough feedback and operating experience, the enhanced error handling could be bundled in an “error extension”
- Other extensions could user the “error extension”
|2009-12-27||kampfcaspar||Created Initial Version|