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