スキップしてメイン コンテンツに移動

PHPのregister_shutdown_functionで登録した関数内でmemory_limitを増加させる

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

コメント