Note that there are some explanatory texts on larger screens.

plurals
  1. POPreventing PHP fatal error traceback output when using custom shutdown handler
    primarykey
    data
    text
    <p>I must be missing something in my understanding of handling PHP errors, specifically suppressing their output. When a fatal error occurs, I expect my shutdown handler function to process it gracefully and terminate script execution. This works as expected. <strong>However, I can't seem to prevent PHP from outputting the information about the fatal error.</strong></p> <p>My php.ini file contains the following directives:</p> <pre><code>error_reporting = E_ALL | E_STRICT display_errors = Off </code></pre> <p>I set <code>error_reporting</code> to report everything and I use a custom error handler to throw exceptions. My expectation is that <code>display_errors = Off</code> will prevent ANY error messages from being displayed.</p> <p>Anyway, when a fatal error occurs the custom error handler is bypassed (because script execution stops immediately) and the shutdown handler executes.</p> <p>Now, on to my simplified code:</p> <pre><code>error_reporting(E_ALL | E_STRICT); ini_set('display_errors', 'Off'); function shutdown_handler() { $err = error_get_last(); $fatal = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR); if ($err &amp;&amp; in_array($err['type'], $fatal)) { echo "\n\ntest fatal error output\n\n"; } exit(); } register_shutdown_function('shutdown_handler'); </code></pre> <p>To test it I generate an "Allowed memory size exhausted" fatal error like so:</p> <pre><code>// max out available memory $data = ''; while(true) { $data .= str_repeat('#', PHP_INT_MAX); } </code></pre> <p>Because i have <code>display_errors = Off</code> I expect this to only produce the following output (as per the shutdown handler):</p> <pre><code>test fatal error output </code></pre> <p>But instead I continue to receive:</p> <pre><code>PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2147483648 bytes) in /home/daniel/mydev/php/test0.php on line 24 PHP Stack trace: PHP 1. {main}() /home/daniel/mydev/php/test0.php:0 PHP 2. str_repeat() /home/daniel/mydev/php/test0.php:24 test fatal error output </code></pre> <p><strong>What am I missing that will prevent this error trace from outputting?</strong></p> <hr> <p><strong>CONCLUSION</strong></p> <p>It appears, as @Cthos sagely noted, that "E_ERROR and display_errors don't play nicely together."</p> <p>This is also the case for E_PARSE (and I assume E_CORE_ERROR/E_COMPILE_ERROR, but I didn't break my PHP installation to test it). I suppose it makes sense that PHP would force the error traceback into STDOUT in these cases because if it didn't you might never know if/why things were going wrong.</p> <p>So a solution in this case would be:</p> <ol> <li>As @Cthos suggested, silence E_ERROR notifications in php.ini: <code>error_reporting = (E_ALL &amp; ~ E_ERROR)</code> or at runtime using <code>error_reporting(E_ALL &amp; ~ E_ERROR);</code></li> <li>Update the shutdown handler to check if the last error was of type E_ERROR and perform the appropriate actions if so.</li> </ol> <p>As for the other fatals like E_PARSE, E_CORE_ERROR, etc. you just have to make sure your code is correct and that your PHP works. If you try to silence E_PARSE errors and handle them in your shutdown function it won't work because parse errors prevent PHP from ever getting that far.</p> <p>So, an updated/working shutdown handler looks like this:</p> <pre><code>error_reporting(E_ALL &amp; ~ E_ERROR); function shutdown_handler() { $err = error_get_last(); if ($err &amp;&amp; $err['type'] == E_ERROR) { $msg = 'PHP Fatal Error: '.$err['message'].' in '.$err['file']. ' on line '.$err['line']; echo $msg, PHP_EOL; } exit(); } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload