I have a gateway script that returns JSON back to the client. In the script I use set_error_handler to catch errors and still have a formatted return.
It is subject to 'Allowed memory size exhausted' errors, but rather than increase the memory limit with something like ini_set('memory_limit', '19T'), I just want to return that the user should try something else because it used to much memory.
Are there any good ways to catch fatal errors?
The correct way is to edit your php. ini file. Edit memory_limit to your desire value. As from your question, 128M (which is the default limit) has been exceeded, so there is something seriously wrong with your code as it should not take that much.
Try prefixing your command with COMPOSER_MEMORY_LIMIT=-1 . This will remove the memory limit for the execution of the command. Update: Memory exhaust errors should now be resolved by using Composer 2.
As this answer suggests, you can use register_shutdown_function()
to register a callback that'll check error_get_last()
.
You'll still have to manage the output generated from the offending code, whether by the @
(shut up) operator, or ini_set('display_errors', false)
ini_set('display_errors', false); error_reporting(-1); set_error_handler(function($code, $string, $file, $line){ throw new ErrorException($string, null, $code, $file, $line); }); register_shutdown_function(function(){ $error = error_get_last(); if(null !== $error) { echo 'Caught at shutdown'; } }); try { while(true) { $data .= str_repeat('#', PHP_INT_MAX); } } catch(\Exception $exception) { echo 'Caught in try/catch'; }
When run, this outputs Caught at shutdown
. Unfortunately, the ErrorException
exception object isn't thrown because the fatal error triggers script termination, subsequently caught only in the shutdown function.
You can check the $error
array in the shutdown function for details on the cause, and respond accordingly. One suggestion could be reissuing the request back against your web application (at a different address, or with different parameters of course) and return the captured response.
I recommend keeping error_reporting()
high (a value of -1
) though, and using (as others have suggested) error handling for everything else with set_error_handler()
and ErrorException
.
If you need to execute business code when this error happens (logging, backup of the context for future debugs, emailing or such), registering a shutdown function is not enough: you should free memory in a way.
One solution is to allocate some emergency memory somewhere:
public function initErrorHandler() { // This storage is freed on error (case of allowed memory exhausted) $this->memory = str_repeat('*', 1024 * 1024); register_shutdown_function(function() { $this->memory = null; if ((!is_null($err = error_get_last())) && (!in_array($err['type'], array (E_NOTICE, E_WARNING)))) { // $this->emergencyMethod($err); } }); return $this; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With