LoginSignup
5
5

More than 5 years have passed since last update.

流れるようにPHP関数を呼び出す

Last updated at Posted at 2013-07-25

メソッドチェーンと「流れるようなインタフェース」は違うものらしいですが。

PHP関数を使っていて、「流れるように使えたらなあ」と思ったこと、ありません?

てことで、作ってみました。

<?php

class piped_call
{
    var $context;
    var $functions;

    public function __construct( $context = NULL )
    {
        $this->context = $context;
    }
    public function __call( $func_name, $args ) {
        if ( isset($this->functions[$func_name]) ) {
            $this->context = $this->functions[$func_name]->call( $args, $this->context );
        } else {
            throw new Exception('Undefined functon call:'.$func_name);
        }
        return $this;
    }
    public function bind( $func_name, pipe $func )
    {
        $this->functions[$func_name] = $func;
    }
}

interface pipe
{
    public function call( $args, $context );
}

class dirname_pipe implements pipe
{
    public function call( $args, $context ) {   return dirname($context);   }
}

class sprintf_pipe implements pipe
{
    public function call( $args, $context ) {   return sprintf($args[0],$context);  }
}

class glob_pipe implements pipe
{
    public function call( $args, $context ) {   return glob($context);  }
}

class array_map_pipe implements pipe
{
    public function call( $args, $context ) {   return array_map($args[0],$context);    }
}

class implode_pipe implements pipe
{
    public function call( $args, $context ) {   return implode($args[0],$context);  }
}

class print_pipe implements pipe
{
    public function call( $args, $context ) {   return print($context); }
}

$f = new piped_call( __FILE__ );    // 初期値を与える

// パイプたちを使えるようにする
$f->bind( 'dirname', new dirname_pipe() );
$f->bind( 'sprintf', new sprintf_pipe() );
$f->bind( 'glob', new glob_pipe() );
$f->bind( 'array_map', new array_map_pipe() );
$f->bind( 'implode', new implode_pipe() );
$f->bind( 'print', new print_pipe() );

// 流れるようにPHP関数を呼び出す
$f->dirname()->sprintf('%s/*')->glob()->array_map('basename')->implode('<br>')->print();

上記を実行すると、

  1. スクリプトの存在するディレクトリを取得(dirname)
  2. ディレクトリ名から、ディレクトリ以下を検索する文字列を作成(sprintf)
  3. スクリプトの存在する同ディレクトリ内のファイルを検索(glob)
  4. パスの最後の文字列を取得(arraymap+basename)
  5. brタグで分割(implode)
  6. 結果を表示(print)

を順次実行します。

上記は以下のプログラムと等価になりますが、思考の順番と関数呼び出しが一致している分、直感的になっていると言えます。カッコの対応も分かりやすいですし。


print(implode("<br>",array_map('basename',glob(sprintf('%s/*',dirname(__FILE__))))));

1関数=1クラス作成なのであまり効率的ではないですが、まあ小ネタということでお許しください。__callを使っているので、流れているように見えてIDEで賢く候補を補完はしてくれないのが残念。
(クロージャは詳しくないのですが、クロージャならたくさんクラス作らなくていいのかもですね)

参考:
PHP変態文法最速マスター

5
5
10

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5