php5→php4な状況で困ること(2)

前回に引き続き、「今になってphp4を使うと困ること」について。今回は本命の「オブジェクトがデフォルトで参照渡しにならないこと」に起因するあれこれです。

foreachで回す

$this->itemsが各要素にオブジェクトを持つ配列だった場合、

foreach ($this->items as $item) {
    $item->setValue('hoge');
}

のようにして、各要素に対して値をセットしようとします。php5だとこれでOKなのですが、php4ではこの後に$this->itemsを覗いても何も変わっていません。$itemは$this->itemsの各要素のコピーであり、そこに変更を加えてもコピー元の$this->itemsには何も影響しません。じゃあ、コピーじゃなくて参照でforeachを回せばいいのかと、

foreach ($this->items as &$item) { … }

にすると今度はsyntax errorで止まってしまいます。php5ではforeachに参照が書けるようになったので、この書き方でも動きます。オブジェクトを回す場合は勝手に参照渡しになるので、最初の書き方でいいのですが、このように記述することで普通の配列についてもforeachを参照で回すことが可能になりました。これって地味ながらもかなり大きいような気がします。

で、php4でちゃんと動かそうとすると、

foreach (array_keys($this->items) as $key) {
    $this->items[$key]->setValue('hoge');
}

という、今ひとつイケてないコードを書くハメになります。

参照返しのメソッド

function &getInstance()
{
    if (!isset($this->obj)) return false;
    return $this->obj;
}

php4.4.0以降では、このメソッドを実行し、falseが返った場合に「Notice: Only variable references should be returned by reference」というE_Noticeが発生します。「リファレンスを返すメソッドなんだからリファレンスを返せよ」という、全くもって正論ではあるのですが「面倒だなぁ」という意識の方が先行します。これがphp5ならメソッドの宣言を「function getInstance()」にするだけで希望の動作になります。戻り値がオブジェクトだった場合は自動的に参照返しになるし、bool値はそのまま値として返ります。

php4でこれを正しく動かそうとすると、独自のエラーオブジェクトを実装し、エラー時はそのオブジェクトへの参照を返す、という面倒なことを強いられます。

また、この変更によりメソッドの戻り値を「return new Hoge()」で指定した場合にも同様のNoticeが発生するようになりました。一時期、XOOPSの拡張モジュールやMojaviでNoticeが大量発生することとなり、各所で混乱を招きました。自力で解決できる人は、Noticeが出ないようにプログラムを変更することで対応できましたが、一般的な対策は「E_Noticeレベルのエラーを出力しない」というところに落ち着いたようです。それってどうなのよ。

これらを踏まえると、結局上記のgetInstanceメソッドは以下のような実装になります。

function &getInstance()
{
    if (!isset($this->obj)) {
        $obj = new MyErrorObj();
        return &$obj;
    }
    return $this->obj;
}

やりたいことに対して、実装が必要以上に大きくなってしまいます。しかも呼び出し側での判定もfalseではなく、エラーオブジェクトかどうかを判定することになり、簡単なエラーチェックをするにもPEARのエラー検出みたいなことをするはめになります。これって、phpの良さを全然引き出せてないんじゃないでしょうか。

まとめ

てな感じで、ざっくりと個人的にphp4でうぜぇなぁ…と思う部分をまとめてみました。でも、
http://ilia.ws/archives/162-Migrating-to-PHP-5.2.1-Slides.html
ここの資料を見てみると、未だに世の中の90%はphp4で占められているという現実の前には無視するわけにもいかないのが実情。

いっそのこと、php4のアップデートを完全に停止して無理矢理5に移行させるぐらいしてもいいんじゃないか? なんて過激な考えが浮かぶこともしばしばです。いくらなんでも普及しなさすぎ。当初はオブジェクト周りの互換性で二の足を踏む部分や、5.0の不安定っぷりが原因だったけど、そろそろレンサバも5に全面移行していいように思うんだけどなぁ。このまま移行できない状況がまだ年単位で続くようだと、phpの将来性も先細るような気がしますよ。