JSONをクライアントに返すゲートウェイスクリプトがあります。スクリプトでは set_error_handler を使用してエラーをキャッチし、まだフォーマットされた戻り値を保持しています。
「Allowed memory size exhausted」エラーの影響を受けますが、 ini_set( 'memory_limit'、 '19T') などのようにメモリ制限を増やすのではなく、ユーザーが試してみてくださいそれは多くのメモリを使用していたためです。
致命的なエラーをキャッチする良い方法はありますか?
この回答 が示唆するように、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
例外オブジェクトはスローされません。
シャットダウン関数の$error
配列で原因の詳細を確認し、それに応じて対応できます。 1つの提案として、Webアプリケーションに対してリクエストを再発行し(、異なるアドレスで、またはもちろん異なるパラメーター)、キャプチャした応答を返すことができます。
ただし、error_reporting()
を高く(-1
の値)にして、(他の人が示唆しているように)set_error_handler()
およびErrorException
を使用して他のすべてのエラー処理。
このエラーが発生したときにビジネスコードを実行する必要がある場合(ロギング、将来のデバッグのためのコンテキストのバックアップ、電子メールなど)、シャットダウン関数の登録だけでは十分ではありません。何らかの方法でメモリを解放する必要があります。
1つの解決策は、緊急メモリをどこかに割り当てることです。
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;
}
この関数を使用して、プロセスがすでに消費しているメモリのサイズを取得できますmemory_get_peak_usageドキュメントは http://www.php.net/manual/en/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