Edited at

PHPでメソッドを動的に生やそう

php.internalsを見ていたらPre proposal for "Class extension functions"というのを見つけてしまったんですよ。

万一RFCまで進んでしまったとしても絶対に受理されることはないと思うのですが、なかなか斬新なアイデアだったので紹介してみたいと思います。


文法


PHP

function DateTime->localTime() {

return $this->format('H時i分');
}

$dt = new DateTime();
echo $date->localTime(); // 12時34分


クラスを継承することなく、クラスそのものにメソッドを生やすことができるという機能です。

何処からこんな発想が来たかといえば当然JavaScriptでしょう。


JavaScript

Date.prototype.localTime = function() {

return this.getHours() + "" + this.getMinutes() + ""
};

dt = new Date;
console.log(dt.localTime()); // 12時34分


と思ったんだけど、本人によるとKotlinの拡張関数が元ネタだそうです。


Kotlin

fun Date.localTime(): String {

return SimpleDateFormat("H時m分").format(this)
}

val date = Date()
println(date.localTime()) // 12時34分


ちなみに、RubyC#などの言語でも似たような機能を使うことができます。


みんなの反応

・extendsしたあとで基底クラスにメソッド追加したら死ぬ。

・privateを簡単に見れるようになってカプセル化が死ぬ。

・JSじゃないんだから普通にextendsすりゃええやん。

・Kotlinのはただの糖衣構文であって、実際にクラスを変更しているわけではない。

・複雑化するリスクに対してベネフィットが少なすぎる。

・デリミタは->より::がいいな。

・バックポートに使えそう。たとえばSplFileObjectはPHP5.1.0で実装されたがSplFileObject::freadはPHP5.5.11で追加された。

runkit_method_adduopz_add_functionで同じことができるよ。

全員がNOという感想でした。

アイデアを出してる人も、あくまで反対のうえで使い道を考えているという態度です。


感想

普通にextendsしろよ、という感想。

既存クラスを書き換えるより素直にextendsしたほうが、少なくとも読む方としてはわかりやすいでしょう。

これが導入されると、あるメソッドが言語仕様なのか拡張関数なのか、ぱっと見でわからなくなります。

それどころか同じメソッドでも、PHPバージョンによって言語仕様か拡張関数かが異なる場合すらあります。

どこかのライブラリが勝手に何かやってたりしたら大惨事です。

実のところrunkituopzなどはこの提案よりずっと強力な機能を提供していたりするのですが、これはあくまで特殊用途向けであって、一般ユーザが軽々しく使うようなものではありません。

デフォルトで誰もが使える機能として入れるようなものではないでしょう。

というかJavaScriptですらprototype使うなって方向に進んでいる昨今、Kotlinの拡張関数があまりにも簡単すぎて大丈夫なのこれ。

それからphp.internalsが見づらいのはどうにかならないのだろうか。

今のままだと話題を追いにくいので、ツリー表示に対応してほしい。