Garadama / Shaking in Agony
Garadama on MySpace

大阪が誇る Sludge/Doom バンド Garadama と、カオティックグラインドバンド Swarrrm によるスプリットアルバム、SHAKING IN AGONY/阿鼻叫喚が 2010/03/19 にリリースされる。レーベルはDIWPHALANX Records

MySpace にて新曲 At the Doze が視聴できる。2 分半に満たない短い楽曲だが、圧迫感と緊張感を伴う濃厚な Sludge/Doom となっている。

Gu/Vo の柿木義博氏は、未だに元 Subvert Blaze として語られるが、今の Garadama にそれを感じさせるものは、そのあまりにも個性的な声質ぐらいで、もはや全くの別バンドに進化していると言える。そう強く感じさせる、Garadama としての個性が突き抜けた 1 曲とである。

,

昨日投稿したメタプログラミングで PHP をもっとオブジェクト指向にだと、以下のようにしか書けませんでした。

$obj = new MyObject(array('foo', 'bar', 'baz'));
echo $obj->join(',')->strtoupper();
// => FOO,BAR,BAZ

どういうことかというと、new の直後でメソッドを呼び出すことができないようで、上記のように 2 行で書かざるを得なくなっていました。

そこで、MyObject クラスを以下のように書き換えました。

class MyObject
{
    private $_selfMember;

    public function __construct($selfMember)
    {
        $this->_selfMember = $selfMember;
    }

    public static function init($selfMember)
    {
        return new self($selfMember);
    }

    public function __call($name, $args)
    {
        $new_args = array_merge(
            array($this->_getSelfMember()),
            $args
        );
        return new self(call_user_func_array($name, $new_args));
    }

    public function _getSelfMember()
    {
        return $this->_selfMember;
    }

    public function __toString()
    {
        return print_r($this->_selfMember, true);
    }
}

変更点は、init というスタティックメソッドを追加しただけです。

この変更により、以下のように書けるようになりました。

echo MyObject::init(array('foo', 'bar', 'baz'))->join(',')->strtoupper();
// => FOO,BAR,BAZ

楽しいような、危なっかしいような感じですが、言いたいこととしては、マジックメソッドを使うといろいろおもしろいことができそうですよ!ということにさせてください。こういう、いかにも役に立たなそう (というかむしろ害悪になりそう) なコードでも、遊びでいろいろ試しているうちに、実用に耐えうるアイディアに化けるかもしれません・・・。

, ,

PHP はブジェクト指向言語です。ですが、Ruby や JavaScript のような、より純度の高いオブジェクト指向言語とは違って、以下のようなことはできません。

puts ['foo', 'bar', 'baz'].join(',').upcase
# => FOO,BAR,BAZ
print(['foo', 'bar', 'baz'].join(',').toUpperCase());
// => FOO,BAR,BAZ

これは、Ruby や JavaScript において、配列や文字列がオブジェクトとして扱われ、メソッドを持つことができるからこそできる書き方です。

同じようなことを PHP でやろうとすると、以下のようなおぞましいことになってしまいます。

echo strtoupper(join(array('foo', 'bar', 'baz'), ','));
// => FOO,BAR,BAZ

Ruby や JavaScript のような、メソッドチェインを使った書き方と、PHP のような関数でラップしていく書き方で決定的に違うのは、やはり可読性でしょう。プログラムに書いた順番通りに処理されるので、ほとんどの人にとって、メソッドチェインの方が可読的であると考えられます。

そこで、PHP でも組み込み関数でメソッドチェインができるよう、以下のようなクラスを用意します。

class MyObject
{
    private $_selfMember;

    public function __construct($param)
    {
        $this->_selfMember = $param;
    }

    public function __call($name, $args)
    {
        $new_args = array_merge(
            array($this->_getSelfMember()),
            $args
        );
        return new self(call_user_func_array($name, $new_args));
    }

    public function _getSelfMember()
    {
        return $this->_selfMember;
    }

    public function __toString()
    {
        return print_r($this->_selfMember, true);
    }
}

このクラスを使うと、以下のようなコードが書けるようになります。

$obj = new MyObject(array('foo', 'bar', 'baz'));
echo $obj->join(',')->strtoupper();
// => FOO,BAR,BAZ

PHP の文法の制約上、ここまでが限界ですが、何とかそれらしくなりました。join も strtoupper も PHP の組み込み関数ですが、あたかもオブジェクトのメソッドのように呼び出すことができています。

この実装を可能にしているのが、PHP のマジックメソッドと呼ばれる、特殊なメソッドです。

__call メソッドは、メソッドが存在しない時に実行されます。引数として、実行しようとしたメソッドの名前と、その引数を受けるので、call_user_func_array に渡して、関数を実行しています。Ruby でいうと method_missing メソッドに相当します。

そして、上記のコードで、__call メソッドの返り値は、MyObject を new した新たなオブジェクトになっているので、このままでは、これを echo することはできません。

ここで、__toString を使うと、オブジェクトを文字列として出力するときの形式を定義できます。ここでは print_r を使っています。Ruby でいうと、to_s メソッドに相当します。 (ここでの動作は inspect メソッド的ですが)

ただし、この MyObject クラスは、あくまでも簡易的なものなので、存在しない関数を実行しようとしたときのエラー処理等をしていません。また、内部で実行する関数への、引数の渡し方によっては、うまく動作しません。例えば、explode や preg_replace など。

いろいろと問題点があって、MyObject 自信は使い物にはなりませんが、マジックメソッドによるメタプログラミングは、PHP によるプログラムの書き方の可能性を、大きく広げていると言えるでしょう。

だからと言って、チーム開発でこのようなコードを書くと、自分以外のメンバーに混乱を招くことになるので、安易に使うのはオススメできませんが・・・。

, ,