PHP変態文法最速マスター

Posted by Hiraku on 2010-02-07
PHP基礎文法最速マスター | Shin x blogより。

変態文法ならもう少しいろいろあると思うので、まとめてみました。ただ、ほとんどがPHPに限らない話かも。。。

この記事はPHP 5.2.12 (cli) で動作確認してます。5.3の文法は他をあたってください。5.3専用フレームワークなどを探せば勉強になるかも。

復習:PHPは何でも文字列

参考:Modern PHP Programming 入門 @ PFI 社内セミナー - 肉とご飯と甘いもの @ sotarok

変数名も、関数名も、クラス名も何でもかんでも文字列です。逆に言えば、文字列を変数名や関数名として使用することができます。可変関数とか可変変数とか言います。

<?php
//可変変数 ////////////////
$abc '変数abcの中身';
echo 
$abcPHP_EOL;
echo ${
'abc'}, PHP_EOL//文字列での直接指定。変数、メンバ変数、メソッドの場合のみ可能。
$name 'abc';
echo ${
$name}, PHP_EOL;
echo $
$namePHP_EOL;   //省略記法

//可変関数 ////////////////
function abc() {        //定義文は可変にできない。
    
echo '関数abcが実行されました'PHP_EOL;
}
abc();
$name 'abc';
$name();

//可変クラス ///////////////
class abc {}
new 
abc();
$name 'abc';
new 
$name();

「_(アンダーバー)」という名前

名前でクォートせずに使える記号はこれだけです。人気が高いのでグローバルの$_や_()はすぐ使われてしまいますが、メソッド名で短い名前が欲しい場合は使えます。5.3で名前空間が一般的になってくれば、もっと使われるようになるかもしれませんね。

メソッドチェーン

「流れるようなインターフェース」などとも言いますが、メソッドの戻り値に$thisを渡すことで、メソッドを連続的に呼び出すことを言います。PHPに限らず有名ですね。

メソッドチェーンはWAFなどでも頻繁に用いられ、ありふれたものになっています。応用例としてはopenpearのPHP_Objectがおもしろいです。

newからのメソッドチェーン

参考:PHP で引数をそのまま返す関数を作っておくと便利 - IT戦記

new構文そのままだとできませんが、関数の戻り値という形にすればメソッドチェーンにつなげることができます。個人的には、独自のコンストラクタを作るのが好き。


<?php
class Chain {
    public static function 
_(){
        return new 
self;
    }

    public function 
p($name) {
        echo 
$name;
        return 
$this;
    }
}

Chain::_()->p('hoge')->p('fuga');

引数で戻り値を受け取る

PHPに限った話ではありませんが、引数を参照で渡すことで、戻り値を受け取ることができます。

賛否が分かれるかもしれませんが、メソッドチェーンと併用するとチェーンが途切れなくなるので美しくなります。

<?php
class Sum {
    private 
$sum=0;
    public static function 
_() {
        return new 
self;
    }

    public function 
add($a) {
        
$this->sum += $a;
        return 
$this;
    }
    public function 
out(&$result) {
        
$result $this->sum;
        return 
$this;
    }
}
Sum::_()->add(1)
        ->
add(2)
        ->
out($result1)
        ->
add(3)
        ->
add(4)
        ->
out($result2);
echo 
"$result1\t$result2";
---- 3 10

オーバーロード/マジックメソッド

PHP用語でオーバーロードと言うと、一般的なオーバーロードとは違い、「未定義/呼び出し禁止のメソッドを呼び出せること」を指します。(呼び名がイケてないせいか、オーバーロードという単語を使わないことが多い気がする)

挙動は各種マジックメソッドによって定義します。

<?php
class Hoge {
    public function 
__call($methodname, array $args) {
        echo 
"$methodname(".implode(', ',$args).")を呼びました\n";
    }
    public function 
__get($name) {
        echo 
"{$name}を読もうとしました\n";
    }
    public function 
__set($name$val) {
        echo 
"{$name}に{$val}をセットしようとしました\n";
    }
}
$hoge = new Hoge;
$hoge->fuga(1,2,3);
$a $hoge->moge;
$hoge->fuga 1;
----- fuga(1, 2, 3)を呼びました mogeを読もうとしました fugaに1をセットしようとしました

わかりにくければ以下の応用例のようなことができるよーと言えばピンとくるかも。

応用例1:readonlyメンバーの作成

マジックメソッドの最も簡単な応用例がこれでしょう。getXXX()などのアクセサを用意せずにreadonlyを実現できます。

<?php
class Hoge {
    private 
$readonly 'readonly';
    private 
$private 'private';
    public function 
__get($name) {
        switch (
$name) {
            case 
'readonly':
                return 
$this->$name;
                break;
            default:
                
trigger_error('そのメンバは読めません');
        }
    }
}
$hoge = new Hoge;
echo 
$hoge->readonly//エラーにならない
echo $hoge->private;   //エラー

ちなみに、見やすさのためにswitch文を使いましたが、PHPのswitch文は悪名高い==比較を使うので、実際のコードではif文で===を使った方がいいです。

応用例2:std::coutもどき

C++のcoutみたいなものを実装できます。文字列によってはクォート不要なところがミソ。ただし、単語ごとに関数呼び出しのコストがかかるため、パフォーマンスはおそらく劣悪。実用性は無いでしょうね。

<?php
class std {
    const 
endl PHP_EOL;
    public static function 
cout() {
        return new 
self;
    }
    public function 
__get($name) {
        echo 
$name;
        return 
$this;
    }
}

std::cout()->あああ->いいい->ううう->{'えええ おおお'}->{std::endl};
---- あああいいいうううえええ おおお

応用例3:DBアクセサ

コードは省略しますが、こういうクラスを書くことは可能です。SQLを頻繁に使うなら、ここまで短くできるという例。


<?php
DB
::connect()->{'SELECT * FROM address WHERE firstname=? AND lastname=?'}
               (
'taro''yamada')
             ->
out($result);
print_r($result);

応用例4:DSL

メソッドチェーンを極めると独自文法っぽいものを作ってしまうことができます。テストのライブラリなどで、よく使われています。有名なPHPUnitにも振舞駆動開発用の記法があり、これがDSLと言えなくもないかも。

参考:http://www.phpunit.de/manual/3.4/ja/behaviour-driven-development.html

まとめ

メソッドチェーンの使い方ばっかりになってしまいました。。そもそもPHPはあまり自由度を高くしないようにしている節があるので、他の言語に比べると可能な文法も限られてきます。ライブラリの作成などで、使用感を少しでも改善したい時に一考するぐらいでしょう。

もちろん、この記事はこれらの文法の使用を推奨しているわけではありません。むやみに使えば可読性は下がりますし、パフォーマンスも劣化します。こういう書き方もできるよ、という可能性を示しているだけなので、用量・用法を守ってお使いください。

keyword: PHP

PHPの最新記事