PHP RFC: Improved Error Callback Mechanism
- Version: 0.4
- Create Date: 2015-03-13
- Modify Date: 2015-06-10
- Author: Patrick Allaert patrick@catchy.io, Olivier Garcia olivier@catchy.io
- Status: Abandoned
- First Published at: http://wiki.php.net/rfc/improved_error_callback_mechanism
Introduction
There are several extensions that replaces the internal PHP error callback (zend_error_cb
, initially set to php_error_cb
), either to customize one of the behaviour (e.g. XDebug changes the generated output) or to add additionnal features (e.g. PECL/apm logs errors in database). Unfortunately they do not play well with each others because PHP has no mechanism that allows proper callback chaining or separation of concern. It also forces extension authors to re implement parts of the original error callback if this one cannot be called.
The current behaviours of php_error_cb
are:
- Detect whether the error is repeated
- Transform the error into an exception depending on the error handling
- Display the error
- Log the error
- Check if the error is recoverable and bail out if needed
- Track the error in a user accessible variable
This RFC aims to ease interactions between PHP and such extensions to make them register their callbacks without interfering with each others. In order to achieve that, an extension must be able to replace an existing behaviour as well as extending it.
Proposal
We propose to split php_error_cb
into multiple hookable categories corresponding to the following behaviours:
- Display the error (display category)
- Log the error (log category)
- Do additional processing if needed (process category), empty by default
- Check if the error is recoverable and bail out if needed (bailout category)
We believe that there is no interesting use case for hooking the other existing categories of php_error_cb
.
An extension that want to extend one of the category can do it so by appending a hook:
ZEND_ERROR_CB_API my_logging_hook(ZEND_ERROR_CB_HOOK_ARGS) /* Do some logging with error line number, filename, message, ... */ } zend_append_error_hook(E_HOOK_LOG, my_logging_hook);
Each hook must return either SUCCESS
or FAILURE
: if FAILURE
is returned, the next hooks of current category won't be called.
Prepending is also possible in the case one want to execute a hook before the others of the same category:
zend_prepend_error_hook(E_HOOK_LOG, my_logging_hook);
An extension that want to clear all hooks from a specific category can do it so with:
zend_clear_error_hook(E_HOOK_DISPLAY);
zend_append_error_hook
, zend_prepend_error_hook
and zend_clear_error_hook
will operate on one of the internal linked lists of error hooks. There will be one linked list for each category, referred to with one of the constants: E_HOOK_DISPLAY
, E_HOOK_LOG
, E_HOOK_PROCESS
or E_HOOK_BAILOUT
. Those linked lists will, by default, contain the original implementation.
The modification of hook lists must be done during the MINIT phase.
Overview of the improved ''php_error_cb''
static void php_error_cb(PHP_ERROR_CB_FUNC_ARGS) { /* checking for repeated errors to be ignored */ /* store the error if it has changed */ /* according to error handling mode, suppress error, throw exception or show it */ /* display/log the error if necessary */ if (display && (EG(error_reporting) & type || (type & E_CORE)) && (PG(log_errors) || PG(display_errors) || (!module_initialized))) { /** calling E_HOOK_LOG hooks here **/ /** calling E_HOOK_DISPLAY hooks here **/ /** calling E_HOOK_PROCESS hooks here **/ } /** calling E_HOOK_BAILOUT hooks here **/ /* tracking the error in $php_errormsg if activated */ }
Open discussions point
Should the implementation also contain pre and post hook lists that would be empty by default? It would enable extensions to do some treatment at the early/lately phase.
Backward incompatible changes
None.
Proposed PHP Version(s)
PHP 7.0.
RFC Impact
To existing extensions
Extensions that want to replace zend_error_cb
are still free to do so, however they are strongly encouraged to benefit from those new hooks to play easily together.
Open issues
None at the moment.
Patches and tests
The patch has been created by Patrick Allaert and Olivier Garcia.
PR available at: https://github.com/php/php-src/pull/1247
Implementation
After the project is implemented, this section should contain:
- the version(s) it was merged to
- a link to the git commit(s)
References
None at the moment.
Rejected features
SOAP hooks
Providing specific hook(s) for the *soap* extension that implements its own error callback is not considered as it explicitly call the previously set error callback.
User land changes
It may be interesting to provide changes in the userland so that a user function can be registered as a category of one of those hooks. However, that would complicate this RFC and we consider this as out of the actual scope while considering it as a future enhancement.
Proposed Voting Choices
Proposed voting choices are Yes (vote in favor) or No (reject the proposed change)
As this is not a language-changing RFC, a majority of 50%+1 is required to approve this RFC.
Vote
Versions
- 0.1: Initial RFC (2015-03-13)
- 0.2: Changing API slightly + possibility to prepend hooks as suggested by Derick + fixing E_HOOK_PROCESS hooks placement (2015-04-07)
- 0.3: Added hook's SUCCESS/FAILURE behaviour (2015-04-23)
- 0.4: Closing vote for version 7.0 (“No go” because of feature freeze)