PHPのAPCの apc.include_once_override 設定時にいくつかの条件を満たした場合に include_once 等が失敗する現象
↓の続き
誤報 APC の apc.include_once_override で動的な include_once 等が失敗する問題
http://d.hatena.ne.jp/narusase/20121030
どうも同僚の調査によると、動的なinclude_onceが原因ではないようだ
・・・というわけで、極限まで単純化したサンプルコードを書いてテストしてみた。
ファイルその1. /home/htdocs/test.php
<?php function include_test($x = array()) { include_once('hogehoge.php'); } echo '1'."\n"; include_test(); echo '2'."\n"; include_test(); echo 'end-'."\n";
ファイルその2. /home/lib/hogehoge.php
<?php class hogehoge { } or <?php const hogehoge = 0;
ざっくりとわかっている条件を列挙する
- 1.二つのファイルにわかれている必要がある(include_onceするので当然だが)
- さらに読みこまれるファイルがカレントディレクトリにある場合は起こらない(パス周辺の条件がある?)
- 2.include_onceする対象は相対パス指定でないといけない(フルパス指定では起こらない)
- なお、当然だが、パスは通っている必要がある
- 3.include_onceするされる相対はclass or constを記述する(functionでは起こらない)
- const のばあい 下記のNoticeになるがFATALではないので動きはする
- Notice: Constant hogehoge already defined in /home/lib/hogehoge.php on line 2
- const のばあい 下記のNoticeになるがFATALではないので動きはする
- 4.関数内でinclude_onceしないと起こらない
- 5.関数内には必ず引数が必要で array() で初期化されている(引数が無い、初期化の値がNULLだとおこらない)
- また、その引数にはコールする際いかなる値も渡してはならない
つまり、5. の条件は不明だがそもそも関数内でinclude_onceされており、さらにパスがini_setなどによるパスの変化によって別ファイルが指定される可能性がある場合に起こっているようだ。
結論としては、発生条件は良く分からないが、下記の条件のいずれかを守れば「回避できそう」ということが分かりました。
1.関数内でinclude_once or require_once を呼ばない。
2.カレントディレクトリ以外のファイルの include_once or require_once はフルパスで指定する
3.どうしても関数内でinclude_once or require_once を呼ぶ場合、引数の初期化を行わないか、必ずarray()以外(NULL推奨)で初期化する