誤報APC の apc.include_once_override で動的な include_once 等が失敗する問題
とあるよくわからないエラーを調査したときPEARのMail.php の@ 指定を解除したところ下記のようなエラーが発生したのでちょいと調べて見た。
結果としては先に設定したAPCの apc.include_once_override = 1 の設定が悪さをしていた事が分かったので一応メモっておく
PHP Fatal error: include() [<a href='function.include'>function.include</a>]: Cannot redeclare class mail_smtp in /省略/Mail.php on line 52
ネット上をいろいろ探してみるといくつかのサイトで引っかかる既知の問題のようだが、PEARのMail.phpの下記のようなコードが駄目らしい。
static function &factory($driver, $params = array()) { $driver = strtolower($driver); @include_once 'Mail/' . $driver . '.php'; ...省略... }
具体的にはこのfactory関数は include_once で関数の引数として渡される文字列からinclude対象のファイル名を作っているのだが、include_once_override はこのような include_once の書き方に対応できないらしい。
まだきちんと原因を追ったのではないがおそらく、APCのinclude_once_overrideの利用時はinclude_onceはincludeと同じような動きをするようになってしまっており二重定義をして起こられている物と思われる。
また、これは動的なinclude_onceだけで起こっているようなので、静的にinclude_onceに続く文字列をキーにしてincludeするかしないかを決定していると考えると現象に説明がつく。(ほんと推測ではなくはソースを当たるべき)
とりあえずは、include_once_overrideを無効化して対処したが、上記のコードはおそらく、下記のようにすることで回避できると思われる。
static function &factory($driver, $params = array()) { $driver = strtolower($driver); switch ($driver) { case 'mail': include_once 'Mail/mail.php'; break; case 'sendmail': include_once 'Mail/sendmail.php'; break; case 'smtp': include_once 'Mail/smtp.php'; break; default: include_once 'Mail/' . $driver . '.php'; // include_once_override 非利用時用の保険 break; } ...省略... }
追記:
いろいろ調べたてサンプルコードを書いたところこちらの原因は誤報でした
動的に変数を使わずinclude_onceしてもこのエラーは起こるようです
もう少し調べたのち、改めてメモ書きます