概要
preg_match, preg_replace などで使用する PHP の正規表現は、 PCRE(Perl Compatible Regular Expression)を使っています。
この PCRE ですが、PHP-5.2 より前とそれ以降では挙動が異なるので注意が必要です。
挙動の違い
PHP-5.2 以降では php.ini で設定可能な項目として下記が追加されました。
- pcre.backtrack_limit
- pcre.recursion_limit
それぞれ名称の通り、バックトラック処理/再帰処理の制限値です。
これらの制限に引っかかった時にはマッチングをあきらめてしまうようで、結果として preg_match であれば 0、preg_replace であれば null が返ってきます。
従って、PHP-5.2 より前のバージョンではこれらの制限がなかったようなので正しく動いていた処理が、PHP-5.2 以降で動かすと正しく動かなくなる、、、といったタチの悪いことが発生します。
しかも、例外が発生するとかではなく、単純にマッチしなかったかのような挙動なので、問題として見つけることが非常に困難です。
対処方法
この問題が起きてしまった時の対処方法ですが、メモリ的に問題がないのであれば単純に php.ini で明示的に設定をして、設定値を増やすことで解消します。
pcre.backtrack_limit=500000 pcre.recursion_limit=500000
Smarty で発生
これは自分だけかもしれませんが、この問題は今のところ Smarty のテンプレート内の処理でしか起きたことがありません。
もしかしたら、Smarty はこの問題が起きやすい作りになっているのかも。。。
pcre.jit
php.ini で設定可能な PCRE 項目として、pcre.jit
という項目があります。
これは、PCRE の just-in-time コンパイラを利用するかどうかのフラグです。
一度正規表現をコンパイル後に利用すると、繰り返しマッチが非常に高速化されます。
ただ、経験上意味不明なエラーが出たこともあったのであまりいいイメージは無かったのですが、下記の情報によると性能的に非常に有用ですので、基本的には無効にするのは良くなさそうです。
https://speakerdeck.com/hanhan1978/pcre-pcre-jit-and-php
デフォルトで pcre.jit
は有効なので、特別な理由がない限りはそのままで良さそうです。
コメント