使用create_function作为闭包时引用包含作用域的变量。 PHP

时间:2011-06-26 20:34:37

标签: php reference closures

使用真正的闭包,我们可以做到,

function foo(&$ref)
{
    $inFn = function() use (&$ref)
    {   
        $ref = 42; 
    };  

    $inFn();
}

因此修改引用而不必在调用$inFn时传递它。

如果我们更换,

    $inFn = function(... 

    $inFn = create_function(...

是否有任何(简单而干净)的方式来做同样的事情;通过引用引用包含范围的变量,而不将其明确地传递给$inFn

3 个答案:

答案 0 :(得分:1)

我遇到了this answer to another question,这激励我想出以下内容。我没有对它进行大量测试,我确信它可以改进(并且exec调用的需要是一种耻辱),但它似乎解决了我的问题。

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())
        );  
    }   
}

你可以像这样使用它:

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>';

返回:

Before, $x = 23
After, $x = 42

或者像这样:

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(); 

返回:

x is 0
z is a1b2c3d
x is 3

答案 1 :(得分:1)

  

是否有任何(简单和干净)方式来做同样的事情;参考a   通过引用包含范围的变量而不显式   将它传递给$ inFn?

简单回答:不。

create_function只不过是eval的包装器,它创建一个伪匿名函数并返回其名称(即'lambda_1')。你不能用它创建闭包(那些是内部Closure类的实例,一个新的语言结构与普通的PHP函数完全不同。我想你是在问这个,因为你想要

在旧的PHP版本上使用闭包*。但由于它们在5.3之前不存在,因此无法使用它们。

如果您可以使用非简单的非清洁解决方案,请查看其他答案。

* )也许这需要一点澄清。 Closure不仅仅意味着匿名函数,它们正是您的问题:记住调用上下文。正常功能无法做到这一点。

答案 2 :(得分:0)

看起来你可以使用$inFn = create_function('&$ref', ...);。你试过这个吗?