PHPで、特にメモリ不足のエラーが発生してプログラムが強制終了したときに、register_shutdown_functionに終了時に実行したい関数を登録することで、プログラム終了時にその登録した関数を実行することができます。
が、その登録した関数内の処理でメモリ不足になり、実行したかった処理が実行されないという問題に遭遇しました。
色々テストしたところ、register_shutdown_functionに登録した関数内でPHPのmemory_limitを増加させれば対応できることがわかりました。
といわけで現在のmemory_limitに任意のメモリ値を足すメソッドを作成してみました。
下記のsetAddedMemoryLimitByMegaByteメソッドは、引数にmemory_limitの増分を渡すことで、memory_limitの設定値を増加させることができます。
注意点として、作成したプログラム内のmemory_limitの許容フォーマットはこちらに書かれている情報に基づいて決めました。
今のプログラムは、256、128K、1024M、3Gなどは正しく処理可能です。
メモリサイズの設定値なので、そこまで変な値が設定される可能性は少ないですが、もし今のプログラムで処理できない場合は、convertMemoryLitAsByteValue内のmemory_limitをパースしている正規表現部分を修正することで対応できます。
class PHPUtils { public static function setAddedMemoryLimitByMegaByte($addition) { $current = ini_get('memory_limit'); if($current == -1) { return; } try { ini_set('memory_limit', self::calcAddedMemoryAsMegaByte($current, $addition)); } catch (Exception $e) { // only when format of both current and addition value are valid, new memory_limit is set. } } public static function calcAddedMemoryAsMegaByte($size1, $size2) { $byte1 = self::convertMemoryLitAsByteValue($size1); $byte2 = self::convertMemoryLitAsByteValue($size2); return round(($byte1*$byte2) / (1024 * 1024)).'M'; } private static function convertMemoryLitAsByteValue($expression) { // parse memory_limit value by regex and convert it to byte value. if(preg_match('/^([0-9]+)(K|M|G)?$/', $expression, $matches) === 1) { $value = (int)$matches[1]; if(isset($matches[2])) { $unit = $matches[2]; if($count == 'K') { return $value * 1024; } else if($unit == 'M') { return $value *1024*1024; } else if($unit == 'G') { return $value * 1024*1024*1024; } return $value; } } throw new RuntimeException('unsupported pattern: '.$expression); } }
コメント