Подтвердить что ты не робот

Безопасное обнаружение ошибки "Разрешенная память"

У меня есть шлюз script, который возвращает JSON обратно клиенту. В script я использую set_error_handler, чтобы ловить ошибки и все еще иметь отформатированный возврат.

Он подвержен ошибкам "Разрешенные размеры памяти", а не увеличивает ограничение памяти с помощью ini_set ('memory_limit', '19T')., я просто хочу вернуть, что пользователь должен попробовать что-то еще, потому что он использовал много памяти.

Есть ли хорошие способы для обнаружения фатальных ошибок?

4b9b3361

Ответ 1

Как этот ответ, вы можете использовать register_shutdown_function() для регистрации обратного вызова, который будет проверять error_get_last().

Вам все равно придется управлять выводами, генерируемыми из-за нарушения кода, независимо от оператора @ (shut up), или 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 не генерируется, потому что фатальная ошибка запускает завершение script, впоследствии попадая только в функцию выключения.

Вы можете проверить массив $error в функции выключения для получения подробной информации о причине и ответить соответствующим образом. Одно предложение могло бы повторно отослать запрос обратно на ваше веб-приложение (на другом адресе или с разными параметрами) и вернуть захваченный ответ.

Я рекомендую сохранить error_reporting() высокий (значение -1) и использовать (как другие предложили) обработку ошибок для всего остального с помощью set_error_handler() и ErrorException.

Ответ 2

Если вам необходимо выполнить бизнес-код при возникновении этой ошибки (ведение журнала, резервное копирование контекста для будущих отладок, отправка по электронной почте или тому подобное), регистрации функции выключения недостаточно: вы должны освободить память в некотором роде.

Одним из решений является выделение какой-либо аварийной памяти где-то:

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;
}

Ответ 3

с помощью этой функции вы можете получить размер памяти, уже занятой процессом, с документацией memory_get_peak_usage. Документация http://www.php.net/manual/en/function.memory-get-peak-usage.php. Я думаю, было бы проще, если бы вы могли добавить условие для перенаправления или остановки процесса до того, как предел памяти будет почти достигнут процесс. :)

Ответ 4

Хотя решение @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