PHPの文字マッチ性能比較

(更新日: 2018/02/14)

バリデーションコードを書いていると文字にマッチするパターンは結構多いです。簡単なベンチマークコードで性能を比較してみました。

文字マッチ性能比較

入力文字列が英数字+”_”+” “(スペース)のみで構成されているかチェックする関数を作って比較します。このチェックの場合、長過ぎる入力以外のリスクはほぼ廃除1できます。参考:ほぼ全てのインジェクション攻撃を無効化/防止する入力バリデーション

実行結果:

このケースの場合、preg_match()が圧倒的に速いです。preg_match()は正規表現をコンパイルしたデータをキャッシュしています。繰り返し実行する場合、mb_ereg()よりも良い性能を期待できます。必ずしもpreg_match()の方が圧倒的に速い訳ではありませんので注意してください。

strspn()が遅いのは文字マッチアルゴリズムの問題です。これは簡単な最適化パッチで高速化できるので、時間があったら作って適用しておきます。

何度もマッチさせるパターンがある場合、結果をキャッシュすると高速化できます。キャッシュと言っても単純にローカルstatic配列変数に結果を保存するだけです。

同じ変数を何度もバリデーションしたり、エスケープしたりするコードの実行速度オーバーヘッドが気になる場合、キャッシュした結果を単純に返すコードにすると良いでしょう。2

結果をキャッシュしてしまえば、遅くて重い複雑なバリデーションでもエスケープでも、使いたい放題です。

メモリ利用

1つのリクエストの処理で仕様する入力値/出力値の数はそれほど多くないので気にする必要があるケースは少ないです。とは言っても入力値や出力値などの変数をキャッシュした場合にどのくらいのメモリが必要になるのか?知っておくと良いです。

実行結果

最初のループには多くのメモリが必要であったことが分ります。この結果から

  • ハッシュキーにした場合、PHP変数のCopy on Writeは機能しない

ことが判ります。

これは、PHPが内部的にはハッシュキーをPHP変数(zval)としてして扱っていないことが理由です。

最初のループはハッシュキーに文字列がコピーされて保存されています。このため、同じ文字列が大量にコピーされメモリ使用量が大幅に増えています。

後のループではハッシュに変数を代入しているのでPHP変数のCopy on Write機能が通常どおり動作し、メモリ利用量はそれほど増えていません。

スタティック変数を利用した処理結果キャッシュはそれなりにメモリが必要であることに注意しましょう。3


  1. 半角スペースを許可していることがリスクを大きく増加させています。半角スペースはトークンの区切り文字であることが多いです。トークンは命令やパラメーターに成り得ます。 
  2. キャッシュしてメモリを余計に消費するので、メモリ効率は悪くなります。トレードオフです。 
  3. メモリ利用量を減らす為、キーではなく値にキャッシュするデータを保存してはなりません。in_array()での検索はO(n^2)なのでキャッシュする意味が無くなります。ハッシュキーでの検索はO(1)です。 

Comments

comments