2010年3月22日月曜日

PHPって何が駄目って on PHP 5.2.X

5年ばかり、PHPで仕事をしてました。してたときは気にしてなかったというか、なんとなく引っかかってたんですが、pythonと比べると、駄目さが解ります。

一つは、名前空間がないこと。

PHP4で書いたスクリプトが、PHP5で動かないというのはままあります。
構文的な違いもさることながら、組み込み関数/クラスをドカドカ増やす。

私がPHP4時代に仕事で書いたスクリプト。
ディレクトリ検索クラスにDirectoryIteratorと付けました。
付けたくなる名前ですよね。ハイもう落ちが解りましたね。

PHP5になったら、定義済みクラスなので、2重定義でピクリとも動かない。
定義済みクラスってなに?includeしてないよ俺?度肝を抜かれました。
こっちが避けるしかないので、DirectoryIterator1とかに改名。

豊富な組み込み関数&クラスがPHPのウリなのかも知れませんが、
いらない人も居るんだよ、って話が抜けてる。
DirectoryIteratorはSPLエクステンションだが、PHP5.3で内蔵にしちゃったらしい。
http://www.php.net/manual/ja/spl.installation.php

大きなお世話です。

PHP5.3で名前空間をようやく実装したらしいですが、
「名前空間専用の区切り文字」が有って、バックスラッシュでした。
http://www.php.net/manual/ja/language.namespaces.nested.php

正直気持ち悪いんですけど。そうせざるを得なかった理由は想像できる。

オブジェクト指向の実装が不完全なので、階層管理が出来なかった。
なので、識別子名レベルでの代替手段を使った。
ピリオドもコロンも使用済みなので、バックスラッシュしか余ってませんでした。
変な文字も使えるようにして、名前空間っぽく使ってね、みたいな。
のかな?

もう一つは、暗黙の型変換の脅威。

PHPは、知らない間に、過激な型変換をしていて、それで知らずにバグることがあります。
例えば、これが通ります。
"" == 0 
あえて型変換を強調して書いてみましょう。
(int)"" == 0 
意味解らないでしょう?
もちろん、わざわざこんなif条件を書くのは変態です。
しかし左辺が変数だったら
$result == 0
よくある話でしょう?

こういう実装になってる事情は解ります。
多分彼らはコレをやりたいのでしょう。
(int)"9" + 3 == 12 
PHPは、左辺を優先して、型変換を繰り返している。
確かにwebベースのプログラミングで、数値変換はよくある話。
手間が省けるのは歓迎です。

入力値に対しては良いです。

これがハマりそうなケースは、関数の戻り値。

PHPの組み込み関数でも、intとfalseを使い分けちゃってるケースが結構あります。
例えば、mb_strpos。見つかると文字の位置を返しますが、見つからないとfalse。
先頭に引っかかった場合は0を返しますが、== falseとかでチェックしてると通りません。

PHP4で書いて、PHP5で動かなくなる話にも、これが関わってきます。
組み込み関数の挙動が微妙に変わってたりする。
エラーの時は、-1を返す、と思ってたらfalseを貰った、とか。
エラーを < 0 で判断してたら、正常で通過しちゃうわけです。

大昔に書いたプログラムを改造する場合にも、この辺りで微妙にバグる可能性もあります。

これは正直、センスを疑いますが、事情は想像できなくもない。
PHP4時代には例外は無いので、戻り値で遣り繰りした。
しかし、式実装全体としては、intとboolが区別できてる癖に、
暗黙の型変換をしちゃうという、チグハグな実装。
かな?

総評として、「安全に」「大規模な」プログラムを書くには、無理がありそう、
と言えます。