Using true closures, we can do,
function foo(&$ref)
{
$inFn = function() use (&$ref)
{
$ref = 42;
};
$inFn();
}
thus modifying the reference without having to pass it in the call to $inFn
.
If we replace,
$inFn = function(...
with
$inFn = create_function(...
is there any (simple and clean) way to do the same thing; refer to a variable of the containing scope by reference without explicitly passing it into $inFn
?
I came across this answer to another question which has inspired me to come up with the following. I haven't heavily tested it and I am sure it can be improved (and the need for the exec
call is a shame), but it seems to solve my problem.
class create_closure
{
private
$_cb = null,
$_use = array();
public function __construct(array $use, $closure_args, $closure_body)
{
$use_args = implode(array_keys($use), ',');
$this->_cb = create_function(
$use_args.($use_args==='' OR $closure_args==='' ? '' : ',').$closure_args,
$closure_body
);
$this->_use = array_values($use);
}
public static function callback(array $use, $closure_args, $closure_body)
{
$inst = new self($use, $closure_args, $closure_body);
return array($inst, 'exec');
}
public function exec()
{
return call_user_func_array(
$this->_cb,
array_merge($this->_use, func_get_args())
);
}
}
You can use it like this:
function foo(&$ref)
{
$inFn = new create_closure(
array('$ref'=>&$ref),
'',
'$ref=42;'
);
$inFn->exec();
}
$x = 23;
echo 'Before, $x = ', $x, '<br>';
foo($x);
echo 'After, $x = ', $x, '<br>';
Which returns:
Before, $x = 23 After, $x = 42
Or like this:
function bar()
{
$x = 0;
echo 'x is ', $x, '<br>';
$z = preg_replace_callback(
'#,#',
create_closure::callback(
array('$x'=>&$x),
'$matches',
'return ++$x;
'
),
'a,b,c,d'
);
echo 'z is ', $z, '<br>';
echo 'x is ', $x, '<br>';
}
bar();
Which returns:
x is 0 z is a1b2c3d x is 3
is there any (simple and clean) way to do the same thing; refer to a variable of the containing scope by reference without explicitly passing it into $inFn?
Simple answer: no.
create_function
is nothing more than a wrapper for eval
that creates a pseudo-anonymous function and returns its name (i.e. 'lambda_1'
). You cannot create closures with it (those are instances of the internal Closure
class, a new language construct completely different from normal PHP functions. I guess that you are asking this, because you want to use closures* on an old PHP version. But since they did not exist before 5.3, you can't use them.
If you can live with a non-simple, non-clean solution, look at the other answers.
*) Maybe this could need a little clarification. Closure does not just mean anonymous function, they are exactly about your question: Memorizing the calling context. A normal function can not do this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With