備忘録 @ ウィキ

bind

最終更新:

mlnk

- view
管理者のみ編集可

関数の引数を束縛する

STLのbind1st、bind2ndみたいな。
使いどころ

  • array_mapとかに toStringの代わりにvar_exportでもいいかもしれない。循環参照があったらだめだけど。
class Binder_Argument {};
 
function& Argument()
{
	static $obj = null;
	if(is_null($obj)) {
		$obj = new Binder_Argument;
	}
	return $obj;
}
 
function toString($a)
{
	$ret = $a;
 
	if(is_string($a)) {
		$ret = "'".$a."'";
 
	} else if(is_array($a)) {
		$content = array();
		foreach($a as $k=>$v) {
			$content[] = toString($k).'=>'.toString($v);
		}
		$ret = 'array('.implode(', ', $content).')';
	} else if(is_bool($a)) {
		$ret = ($a?'true':'false');
	} else if(is_null($a)) {
		$ret = 'null';
	} else if(is_object($a)) {
		$ret = 'unserialize(\''.serialize($a).'\')';
	}
 
	return $ret;
}
 
function bind($func)
{
	$num_args = func_num_args();
 
	$comp_obj = Argument();
 
	$args = array();
	$arg_for_code = array();
 
	for($i=1; $i<$num_args; ++$i) {
		$arg = func_get_arg($i);
 
		if($arg===$comp_obj) {
			$count = count($args);
			$arg_for_code[] = "\$arg{$count}";
			$args[] = "\$arg{$count}";
		} else {
			$arg_for_code[] = toString($arg);
		}
	}
 
	$args = implode(', ', $args);
 
	if(is_array($func) && is_object($func[0])) {
		$code = 'static $o = null; '
				.'if(is_null($o)){'
				.'$o=unserialize(\''.str_replace("'", "\\'", serialize($func[0])).'\');'
				.'}'
				.'return call_user_func(array($o, '.toString($func[1]).')';
	} else {
		$code = 'return call_user_func('.toString($func);
	}
	$code .= ', '.implode(', ', $arg_for_code).');';
 
	return create_function($args, $code);
}

使い方
固定したくない引数にArgument()を指定する。

function func($a, $b) {
  echo "{$a}-{$b}";
}
 
class obj {
  var $c;
 
  function obj($c) {
    $this->c = $c;
  }
 
  function func2($a, $b) {
    echo "static: {$a}-{$b}";
  }
 
  function func3($a, $b) {
    echo "class: {$a}-{$b}-{$this->c}";
  }
}
 
$f = bind('func', Argument(), 'bar');
$f('foo');  // foo-bar
 
$f = bind(array('obj', 'func2'), 'bar');
$f('foo');  // static: foo-bar
 
$o = new obj('bazz');
$f = bind(array($o, 'func3'), 'bar');
$f('foo');  // class: foo-bar-bazz

目安箱バナー