PHP - (2008/05/09 (金) 17:04:12) の編集履歴(バックアップ)
Tips
ユーザ関数の引数を参照渡しで呼び出す
call_user_func では引数を参照渡しできない。
なので、call_user_func_arrayの第二引数へ参照を含む配列を渡す。
function bbb(&$str)
{
$str = 'bbb';
}
$str = 'aaa';
call_user_func('bbb', $str);
echo $str; // aaa : call_user_funcは参照を引数に取れない
call_user_func_array('bbb', array($str));
echo $str; // aaa : 参照の配列を渡していない
call_user_func_array('bbb', array(&$str));
echo $str; // bbb : OK
関数の引数を束縛する
STLのbind1st、bind2ndみたいな。
使いどころ
- array_mapとかに
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