メソッドチェーンと「流れるようなインタフェース」は違うものらしいですが。
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();
上記を実行すると、
- スクリプトの存在するディレクトリを取得(dirname)
- ディレクトリ名から、ディレクトリ以下を検索する文字列を作成(sprintf)
- スクリプトの存在する同ディレクトリ内のファイルを検索(glob)
- パスの最後の文字列を取得(arraymap+basename)
- brタグで分割(implode)
- 結果を表示(print)
を順次実行します。
上記は以下のプログラムと等価になりますが、思考の順番と関数呼び出しが一致している分、直感的になっていると言えます。カッコの対応も分かりやすいですし。
print(implode("<br>",array_map('basename',glob(sprintf('%s/*',dirname(__FILE__))))));
1関数=1クラス作成なのであまり効率的ではないですが、まあ小ネタということでお許しください。__callを使っているので、流れているように見えてIDEで賢く候補を補完はしてくれないのが残念。
(クロージャは詳しくないのですが、クロージャならたくさんクラス作らなくていいのかもですね)
参考:
PHP変態文法最速マスター