PHPの言語仕様がウンコな理由個人的トップ10

「PHPerの問題点はPHPしか知らずに的外れなことを言うことだ」と、Javaしか知らなくて的外れなことを言っている連中にすら言われちゃってるPHPerのみなさん、こんにちは。

PHPは「使える道具」であることは事実です。しかし同時に言語仕様がウンコなのも事実。
ここでは、個人的にウンコだと思っているPHPの仕様を挙げてみたよ!


htmlspecialchars() の名前が長すぎる

これはほんとウンコ。おまえWebアプリのための言語やろが!なんでこの関数の名前がこんなに長いねん!こんだけ長かったらめんどくさがって echo $var としてまうやろが!WordPressのthemeでHTMLエスケープ忘れが多いのはおまえの名前が長すぎるせいだ!

そんなわけで、全PHPerはこんな関数を定義するといいと思うよ。

## echo $var; よりも短く h($var); と書ける!
function h($arg) {
  echo htmlspecialchars($arg);
  # or echo htmlspecialchars($arg, ENT_QUOTES);
}

やっぱり安全なほうは短く簡潔に、安全じゃないほうは長くめんどくさくなるようにすべきだよね。

try-catch はあるくせに finally がない

意味分からん。finallyないと例外処理の魅力が半減してまうやん。PHP開発陣は何を考えているんだろうか。
finallyを実装するのってそんなに難しいの?

ほとんどの関数がエラー時に例外を投げない

最初から例外機構がなかった言語なんだからどうしようもない。せっかくtry-catchがありながら、未だに関数の戻り値をチェックしなければいけないんだから、ウンコだよなあ。

配列がListとMapの両方を兼ねている

これはawkとかを真似たんだろうけど、はっきりいって失敗。この仕様のせいで、たとえばソート関数がごちゃごちゃになっているし、そもそもreadabilityが低くなっている。

## listとして使おうとしているのか、それともmapとして
## 使おうとしているのか、あとのコードを見ないとわからない。
## (つまりreadabilityが低い)
$arr = array();

'&&' や '||' の評価結果が必ず TRUE または FALSE

これはなんでこんな仕様にしたんだろうなあ。これじゃあまるでJavaじゃないか。

## たとえば他のスクリプト言語ならこう書けるのに
$tmpdir = $ENV{TEMP} || $ENV{TMP} || '/tmp';     # Perl
$tmpdir = $ENV['TEMP'] || $ENV['TMP'] || '/tmp'  # Ruby
e = os.environ; tmpdir = e.get('TEMP') or e.get('TMP') or '/tmp' # Python
## PHPだとこうですよ。まるでJavaのようなめんどくささですよ。
$tmpdir = $ENV['TEMP'];
if (! $tmpdir) $tmpdir = $ENV['TMP'];
if (! $tmpdir) $tmpdir = '/tmp';
## 5.3からはこう書けるけど、もっと早くに登場してほしかった。
## これ使ってコード書くのが許されるようになるのは、少なくとも2年後だろう。
$tmpdir = $ENV['TEMP'] ?: $ENV['TMP'] ?: '/tmp';

静的言語なら論理式の結果を強制的にbooleanにする意味はわからんでもないけどさ、動的言語PHPではあんまり意味ないだろ。

三項演算子の結合規則が変

## たとえばこんなのがあったとして、
$x = 1;
$v = $x > 0 ? 'positive' :
     $x < 0 ? 'negative' :
              'zero';

## これはふつう、こうだと期待する (し、他の言語ではそう動作する)
$v = $x > 0 ? 'positive' : ($x < 0 ? 'negative' : 'zero');

## しかぁし、ウンコなPHPではこう評価される
$v = ($x > 0 ? 'positive' : $x < 0) ? 'negative' : 'zero';

## 実行結果は 'negative'。おかしいやろ?
echo $v;

すごい素人くせー仕様。

(new ClassName())->method() ができない

これ、どういう理由があってこうなっているんだろう?こういう*意味不明な制約*が、PHPがウンコな原因なんだよな。

配列の作成がarray()

おまえそれでもスクリプト言語か!とっとと [ ] を導入しろや!

## これはださい
echo tag('input', array('name'=>'name', 'type'=>'text'));
## これならまだ許せる
echo tag('input', ['name'=>'name', 'type'=>'text']);

できれば [ ] と { } の両方を導入してくれるとreadabilidyが上がるんですけど、無理ですかそうですか。

$arr = ['A', 'B', 'C'];     ## これはlistとして使う配列
$arr = {'A'=>10, 'B'=>20};  ## これはmapとして使う配列
$arr = array(10, 'B'=>20);  ## これは混在させて使う配列

存在しないキーを使って配列にアクセスするとwarning

error_reporting(E_ALL);
$arr = array('A'=>123);
$val = $arr['B'];   #=> Notice: Undefined index

これなあ。気持ちはわかるんだけど、だったらnoticeが出なくてかつ簡単にアクセスできる方法を用意してほしいよね、Pythonのdict.get()のように。

## めんどくせー
$val = isset($arr['B']) ? $arr['B'] : NULL;
## 動作おせー
$val = @$arr['B'];

関数名がいいかげんすぎ

歴史的な理由があるにせよ、PHPの関数名は統一感がなくて残念。その残念な仕様を立派なドキュメントでカバーしているから、みんなあんまり文句言わないんだろうけど。
今からでも遅くないから、文字列関連はstr_xxx()、配列関連はarr_xxx()で統一してくれればいいんだけどな。

あー、array_xxx()は長いから却下したい。

配列を代入したらコピーされる

んー、これは慣れといえば慣れなんかもしれん。でもなあ、コンテナの挙動がデフォルトで丸ごとコピーってのはどうなん?コンテナであるはずの配列をスカラー値のような扱いにしてほしくないんだよね。
配列が勝手にコピーされて嬉しかったことなんか一度もないや。

and や or のあとに throw が置けない

つまりだな、「式 or die()」はOKなのに「式 or throw new Exception()」はNGっつーのが残念なんだよね。たぶんthrowは文であって式じゃないからなんだろうけどさ。

## こういうのを
$user = User::get_by_id(123);
if (! $user) throw new Exception("123: not found.");
## こう書きたい
$user = User::get_by_id(123)  or
    throw new Exception("123: not found.");
## こうだとエラー行番号がずれるし。
function raise($errclass, $errmsg) {
    throw new $errclass($errmsg);
}
$user = User::get_by_id(123)  or
    raise('Exception', "123: not found.");

でもまあこれでウンコ呼ばわりするのはちょっと言い過ぎか。

配列関数の第1引数が配列じゃない

array_xxx()の第1引数が配列じゃないっていうのは何か理由があるのかな。配列を対象とした関数なんだから、それを第1引数にしてほしいんだけど。

クロージャがない(なかった)

なくてもなんとかなるのも確かだけど、あったほうがずいぶん楽なのも確か。
個人的には function() { return ; } は長すぎて読むのも書くのも楽じゃないので、もっと簡潔に書ける記法が良かった。

## JavaScriptでもそうなんだけど、これって読みにくくね?
$users = arr_sort_by(User::find_all(),
                     function($user) { return $user->name; })
## これに関してはやっぱりRubyが書きやすく読みやすい
users = User.find_all().sort_by {|user| user.name }


 * * * * *


10個じゃ足りんかったね。なんかほかにもあった気がするけど、忘れた。思い出したら追記するかも。

あと繰り返すけど、「言語仕様の優劣」と「道具としての優劣」は別の話だからね。いい言語仕様だからといって必ずしもいい道具なわけではないし、ましてやいいアプリケーションが生まれるわけでもない。

  • PHPは言語仕様がウンコだけど、ドキュメントはすごく頑張ってるし、道具としてはけっこう使い物になる (使い道を間違えなければ)。
  • Rubyの言語仕様はすごくいいけど、cgi.rbがアレだし、ドキュメントにはサンプルコードが少ないし、実は初心者にとっては厳しい道具かも。
  • Pythonの言語仕様もすごくいいけど、標準ライブラリにはセッション機能が欠けてるし、プロセス起動がかなり重いし、import cgiはトロいしで、レンタルサーバでちょろっとCGI作りたいときにはあんまり向かない道具だよな。
  • Javaはheavyでwordyな言語仕様だけど、EclipseXMLとDIコンテナとHotDeployとSAStrutsを使えばスクリプト言語よりもLightweightな道具だよ!

  ・・・と、スクリプト言語をろくに知らない人間が主張してたりしてなかったり。

#いやおまえ、その前提条件からしてLightweightじゃないことに気づけよ。