Skip to content

Clarifications on the error/exception handler stacks #4883

@SteenSchutt

Description

@SteenSchutt

From manual page: https://php.net/function.set-error-handler

When reading the documentation on set_error_handler(), there is no indication that the function will actually push an error handler to a stack of error handlers. One might realize that this is the case if they also stumble upon restore_error_handler(), but there is nothing on the former to suggest that this it how it works. In fact, the documentation seems to imply that an error handler is set and reset and not pushed and popped.

This could lead one to believe (and did leave me to believe) that the correct way of restoring the error handler is to store the returned previous error handler, and then set it again with set_error_handler($previous). Having taken a look at php-src I learned that this is not ideal, and in a loop or long-running process would cause a memory leak as the stack grows.

This line was particularly confusing to me, as it seems to imply that passing null to the function would reset the error handler stack (or simply remove my error handler):

If &null; is passed, the handler is reset to its default state.

So I have five suggestions for improvements:

  1. Add a short paragraph to the body that explains that error handlers are stored on a stack, and that set_error_handler will push to the stack, and restore_error_handler will pop from the stack. My C++ is nowhere near good enough to tell whether this also applies when passing in null, but if it does (as is my impression), that should be noted as well.
  2. Consider updating language like "Sets a user function (callback) to handle errors in a script." to something that doesn't as much imply that you are replacing the old error handler. I don't know what wording would be good here, since it functionally replaces it unless you call the previous one yourself, but technically it does not replace it. I just think that the word "set" somewhat implies that you are replacing a value with a new one. With some of the other changes, these semantics may not be important.
  3. Update the description for the callback parameter. A better explanation could be something along the lines of "Specifies the callback to be pushed on top of the error handler stack. If null is passed, PHP's default error handler will be used in this manner."
  4. Add a red warning box, that explains that restoring the previous error handler using set_error_handler($previous) is incorrect and why, along with a reference to the restore_error_handler() page.
  5. Add an example that demonstrates that the returned previous error handler should/could be used to invoke it within the new error handler, to maintain the existing behaviour from errors while still adding custom behaviours (with the caveat that this only works if the previous handler is user-defined).

It would also make sense to reference this detail from the restore_error_handler() documentation. It is kind of implied by the fact that you can restore the previous handler without providing it, but I think it would be helpful for most people if it was spelled out.

Finally, the exact same appears to be the case for set_exception_handler() and restore_exception_handler(), so they should probably get the same treatment.

Function definitions for context:
https://github.com/php/php-src/blob/d77d44e1f74305a4c3f43f43a313277283a428f5/Zend/zend_builtin_functions.c#L1307-L1333
https://github.com/php/php-src/blob/d77d44e1f74305a4c3f43f43a313277283a428f5/Zend/zend_builtin_functions.c#L1375-L1396

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions