====== PHP RFC: Improved Error Callback Mechanism ====== * Version: 0.4 * Create Date: 2015-03-13 * Modify Date: 2015-06-10 * Author: Patrick Allaert , Olivier Garcia * 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. [[http://xdebug.org/|XDebug]] changes the generated output) or to add additionnal features (e.g. [[http://pecl.php.net/package/APM|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 ====== * Yes * No ===== 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)