我有一个网关脚本,它将JSON返回给客户端。在脚本中,我使用set_error_handler捕获错误,并且仍然具有格式化的返回值。
它受到“允许的内存大小用尽”错误的影响,但是与其使用ini_set('memory_limit','19T')之类的方法来增加内存限制,我只是想返回用户应该尝试其他方法的原因,因为它过去经常记忆。
有什么好的方法可以捕获致命错误?
我有一个网关脚本,它将JSON返回给客户端。在脚本中,我使用set_error_handler捕获错误,并且仍然具有格式化的返回值。
它受到“允许的内存大小用尽”错误的影响,但是与其使用ini_set('memory_limit','19T')之类的方法来增加内存限制,我只是想返回用户应该尝试其他方法的原因,因为它过去经常记忆。
有什么好的方法可以捕获致命错误?
Answers:
就像这个答案所暗示的那样,您可以使用register_shutdown_function()
注册一个check回调error_get_last()
。
无论是@
(shutdown)运算符,还是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';
}
运行时,输出Caught at shutdown
。不幸的是,ErrorException
没有抛出异常对象,因为致命错误触发了脚本终止,随后仅在关闭函数中被捕获。
您可以$error
在关闭功能中检查阵列以获取有关原因的详细信息,然后做出相应的响应。一个建议可能是针对您的Web应用程序(在不同的地址或使用不同的参数)重新发出请求,然后返回捕获的响应。
我建议保持error_reporting()
较高的值-1
(值为),并使用(如其他人所建议的)对set_error_handler()
和进行其他所有操作ErrorException
。
如果您需要在发生此错误时执行业务代码(记录日志,备份上下文以供将来调试,通过电子邮件发送等),则注册关闭功能还不够:您应该以某种方式释放内存。
一种解决方案是在某处分配一些紧急内存:
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;
}
array (E_NOTICE, E_WARNING)
实际上会收到折旧通知书和其他不需要的小问题。在某些情况下,您可能需要重写以删除!!否定并将其替换为in_array($err['type'], array (E_ERROR))
new SplFixedArray(65536);
。每个空数组元素在我的系统上消耗16个字节。
您可以使用此函数获取进程已消耗的内存大小memory_get_peak_usage文档位于http://www.php.net/manual/zh/function.memory-get-peak-usage.php,我认为这会如果您可以添加一个条件来重定向或停止该进程,而该进程几乎达到了内存限制,则将变得更加容易。:)
虽然@ alain-tiemblo解决方案可以完美地工作,但我放置了此脚本来展示如何在对象范围之外的php脚本中保留一些内存。
// memory is an object and it is passed by reference
function shutdown($memory) {
// unsetting $memory does not free up memory
// I also tried unsetting a global variable which did not free up the memory
unset($memory->reserve);
}
$memory = new stdClass();
// reserve 3 mega bytes
$memory->reserve = str_repeat('❤', 1024 * 1024);
register_shutdown_function('shutdown', $memory);
<?php
function getMemory(){
return ((int) (memory_get_usage() / 1024)) . 'KB';
}
// memory is an object and it is passed by reference
function shutdown($memory) {
echo 'Start Shut Down: ' . getMemory() . PHP_EOL;
// unsetting $memory does not free up memory
// I also tried unsetting a global variable which did not free up the memory
unset($memory->reserve);
echo 'End Shut Down: ' . getMemory() . PHP_EOL;
}
echo 'Start: ' . getMemory() . PHP_EOL;
$memory = new stdClass();
// reserve 3 mega bytes
$memory->reserve = str_repeat('❤', 1024 * 1024);
echo 'After Reserving: ' . getMemory() . PHP_EOL;
unset($memory);
echo 'After Unsetting: ' . getMemory() . PHP_EOL;
$memory = new stdClass();
// reserve 3 mega bytes
$memory->reserve = str_repeat('❤', 1024 * 1024);
echo 'After Reserving again: ' . getMemory() . PHP_EOL;
// passing $memory object to shut down function
register_shutdown_function('shutdown', $memory);
输出为:
Start: 349KB
After Reserving: 3426KB
After Unsetting: 349KB
After Reserving again: 3426KB
Start Shut Down: 3420KB
End Shut Down: 344KB
new SplFixedArray(65536);
。每个空数组元素在我的系统上消耗16个字节。