tmpl2.class.incが最近のPHPでNotice(Undefined offset)を吐くので修正した

私の管理しているサイトで利用している、PHPのテンプレートクラス(PHP4テンプレートクラスライブラリ)が、サーバ移行でPHPのバージョンが上がったためか、Noticeを吐くようになったので、対処したメモ。もしかしたら、参考になる人もいるかもしれないので、公開します。

上記のテンプレートクラスについて簡単に書いておくと、PHP上でテンプレート的なものを簡単に実現してくれる仕組み。PerlでいうHTML::Templateに似てます。

かなり規模の小さいページであっても、ロジックとビューは切り離した方が、メンテナンスする際には便利。というわけで、上記のライブラリは大変便利に利用させて頂いております。

今回の問題は、サーバを更新した際に起こりました。PHPのバージョンが変わったことに起因していると思います。もしかしたら設定で変えられる範囲内かもしれないけど、そこまでは見ていません。

  • 移行前の環境: Ubuntu8.04LTS(PHP 5.2.4-2ubuntu5.27)
  • 移行後の環境: Ubuntu12.04LTS(PHP 5.3.10-1ubuntu3.6)
移行後の環境で上記のテンプレートクラス(tmpl2.class.inc)を走らせると、以下のようなNoticeが出ます。

PHP Notice:  Undefined offset: n in /var/www/virtualhosts/domain/tmpl2.class.inc on line nnn
配列の範囲外参照が起こっているようです。

Noticeは画面には出ないみたいで、気づかない場合も多いでしょう。コマンドライン(php-cli)で動かしたりすると見えます。これも設定次第でしょうが。

そのライブラリのソースを見てみると、一番分かりやすいのがこの部分。

for ( $j = 0 ; $loopbuf[$j] ; $j++ )
ループの継続条件として、配列の範囲外を参照したときに「偽」になる、という動きに依存したコードになっています。

CとかJavaで育った人は、おそらくこういうコードは書かない(範囲外で例外が飛んだりするし)と思うのですが、PHPでこれまで何も問題なく動いていたということは、PHPの文化として許容範囲のコードだったのでしょう。かつては。

私が知る限り、PHP4の時代から、後方互換性についてはあんまり意識されていないメンテナンスが多かったように思います。もちろんプログラミング言語なんて、多かれ少なかれそういう物なのですが、「ちょっとそこを変えないでよ」という問題で頭をかかえたり、PHPを捨てて他の言語に移った人も少なくないでしょう。今回の問題もその一環だと想像しています。

この問題を修正することはそう難しくありません。例えば以下のように修正すればよいです。

for ( $j = 0 ; $j < count($loopbuf) ; $j++ )
これで、配列の範囲外への参照はなくなります。

あと、もう一カ所直しました。基本的には同じ感じで修正しています。(ただし、これはちょっと言語依存的なやり方です。評価の短絡をしているものと信じて&&でつなげています。)


修正前
for ( $i = 0 ;
is_array( $this->loopitem[$loopmode][$i] ) ; $i++ )
修正後
for ( $i = 0 ; 
$i < count($this->loopitem[$loopmode]) &&
is_array( $this->loopitem[$loopmode][$i] ) ; $i++ )
利用の仕方によっては、他にも直す箇所がでてくるかもしれませんが、私の利用している範囲ではこの2カ所に手を入れることで、上記のNoticeが出なくなりました。
 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です