PHPがどうにも好きになれない理由

仕事柄PerlPHPも使うんだけど、どうにもPHPが好きになれない。
いったいなんでだろうか。先にPerlから入ったもんだから後から入ったPHPに対して不満があるのかな?
ま、とにかく両方やっててPHPが微妙だなぁと思う部分を列挙してみよう。
ただPHPに関してそれほど詳しくないので間違っている部分もあるかもしれません。
あ、ちなみにここでいうPHPってのはPHP4(PHP4.4.1)のことです。

  • 変数のtypeミス(strict 'vars')

これが一番痛い。
まさしくPerlでstrictを使わずに実装してるような、そう、まるで先祖帰りしてるような感覚になってしまうので本当につらい。

  • 変数のスコープ

変数のスコープが関数単位でしか発生しないのが痛い。
これによりif条件の場合のみとかループ中でしか使わない変数とかを定義できない。

つまり、変数の存在範囲を細かく設定できないのだ。

  • 配列とハッシュの区別

僕はPerlで実装する時は配列とハッシュを良く使い分けてます。
例えばref関数でARRAYなら配列用の処理、HASHならハッシュ用の処理をするようなケースがあったとします。

 # 例えばこんなん
 if( ref $param eq 'ARRAY' ) {
     print $param->[0];
 }elsif( ref $param eq 'HASH' ) {
     print $param->{hoge};
 }

こういうことをPHPでやろうと思ったときにできない、何故できないかというとPHPは配列もハッシュ(連想配列)も同じだから。
array関数で定義する際に、

 $param = array('a','b','c');

とすれば配列だし、

 $param = array( 'key1' => 'a', 'key2' => 'b', 'key3' => 'c' );

とすればハッシュになるので、現在$paramが配列なのか、ハッシュなのかを判別する完璧な手段が無いのです。
一応それっぽいやり方として、

 function is_hash (&$array) {
     reset($array);
     list($key,$val) = each($array);
     return is_numeric($key) ? false : true;
 }

みたいな感じでやれば殆どの場合判別できるんですけど、でもこれでもハッシュのキーに数値を使っていた場合は配列に誤認識されることになります。

  • 例外処理

これもPHPが好きになれない大きな理由のひとつ。
一応set_error_handlerってのがあるんだけどグローバルに定義するものなので局所的には使いにくい。
また、エラーハンドラ用の関数を予め定義しておかないといけないのもめんどくさい。

 # Perlの場合 
 eval {
    a();
 };if($@){
     print 'a';
 }
 
 # PHPの場合
 function a_error($no,$string,$file,$line) {
     print 'a';
 }
 set_error_handler('a_error');
 a();
 restore_error_handler();

で、もうひとつ。
例外処理終了後の処理の制御ができないのもイタタタです。

 # Perlの場合
 sub a {}
 sub b {}
 sub c { die "c\n" }
 sub d { die "d\n" }
 
 eval {
     a();
     b();
     c();
     d();
 };if($@){
     my $string = $@;
     chomp $string;
     print $string;
 }
 print '_hoge';

これを実行すると「c_hoge」と表示される。
で、これをPHPでやるとしたら・・・、

 # PHPの場合
 function error_handler($no,$string,$file,$line) {
     print $string;
 }
 function a() {}
 function b() {}
 function c() { trigger_error('c'); }
 function d() { trigger_error('d'); }
 set_error_handler('error_handler');
 a();
 b();
 c();
 d();
 restore_error_handler();
 print '_hoge';

「cd_hoge」と表示される。
何故こんなことになるかというと、set_error_handlerでエラーハンドラを設定した場合、エラーを補足後、エラーのあった場所に戻って処理が続行されるから、です。

したがってPHPの場合は例外処理のやり方としてクラス設計段階から常に戻り値にエラーフラグを返すようにするなどの処置が必要となります。

 function a () {
        :
        :
     return array($error_flag,$ret);
 }
 
 list($error_flag,$data) = a();
 if($error_flag) {
     print 'error!';
 }

実際PEARのDBクラスとかは例外が発生した場合に常に戻り値にエラークラスを返すような仕様になってますな。

  • 関数のリファレンス

関数のリファレンスが使えない。
一応、Perlのシンボリックリファレンスみたいな感じで文字列から関数を呼ぶことはできるのでそれで代用は可能。

  • 無名関数

一応create_functionってのがあるんですが、あれって結局グローバルな空間に関数名として使えない文字列で関数を定義してるだけなんで、
使えば使うほどガンガン関数が定義されていくのでちょっと微妙です。

 $a = create_function(
     '$b=9',
     'print $b;'
 );
 $a(); // 9と表示される

create_functionで定義される関数名の仕様が「NULL文字lambda_連番」なので、

 $a = create_function(
     '$b=9',
     'print $b;'
 );
 $hoge = "\x00lambda_1";
 $hoge() // 9と表示される

って感じでアクセスできたりします。

個人的によくクロージャを使うのでこれができないのは悲しいですね。
一応ググってみたらhttp://blog.xole.net/article.php?id=419とかあったりしてそれらしいことは出来るみたいなんですが、
どっちにせよ楽に実装することはできないようです。

便利なライブラリ群が無い、いや、一応PEARっていうのがあるんだけどCPAN程豊富じゃないしPEARに属さない一匹狼クラスとかも多くてわかりにくい。

このほかにも細かいことを言うとメソッドチェーンができなかったり、多重継承(Mix-in)できなかったり、qw//使いてぇーだったりと、
まあ色々あるんですけどそこは言語が違うんだから受け入れるしかないですよね。

と、ここまで書いてみて結局PHPが嫌いなのか?と思われるかもしれないが嫌いではない、ただ好きになれないだけってこと。
先にPerlを知っちゃったもんだからPHPにも同じものを求めてしまっているのかも。
逆にPHPPHPPerlには無い良い部分もあるし。
foreachの構文とかはPHPの方がキーと値をワンセットで取ってこれるのでいい感じ。
is_arrayとかもお気に入り。言語仕様でswitchがサポートされてるのも良い。

あぁ、なんか結局PHP嫌い的な文章になってしまったけどとりあえずPHP5では例外処理とかサポートされたんで、
今度はPHP6でstrictあたりをサポートしてくれたらたぶんそれなりに好きになりそうな予感。