PHP数组引用;在数组中保存引用以供以后使用


PHP array references; holding references in an array for later use

我正在尝试保留一个变量引用以供以后使用。

不确定这是可能的,但我希望我可以初始化一个数组元素,并引用它与一个变量。然后,将所述数组元素的值设置为某个值,从而使所引用的变量可以访问该值。

例如:

class Test{
    private $_vars = array();
    public function bind($key, &$var){
        $this->_vars[$key] = &$var;
        return $this;
    }
    public function fetch($key, &$var){
        $var = $this->_vars[$key];
        return $this;
    }
}
$test = new Test();
$string_set = 'This is a string';
$test->bind('string', $string_set)
    ->fetch('string', $string_get);
var_dump($string_get);
// expected:  string(16) "This is a string"
// actual:    string(16) "This is a string"

问题来了;方法调用的顺序。我不能让call()函数返回对$this的引用,因为call()函数需要传递存储的匿名函数的返回值(否则我会将调用重新排序为->call()->fetch()而不是->fetch()->call() )

无论如何,fetch()方法应该在$_vars中通过键设置适当的元素到NULL (清空任何现有值,或初始化它,无论),然后将该元素引用到传递的$var

当匿名函数被调用时(fetch()绑定完成后),它调用bind(),现在将$_vars中的元素绑定到任何(在这种情况下包含This is a string$string_set )如果我的逻辑是正确的,fetch()绑定变量( $string_get在这种情况下)现在应该引用$_vars中的数组元素引用$string_set包含This is a string

似乎不是这样的。下面是失败的代码(为了简洁,把去掉了,但所有重要的部分都在那里)

class Test{
    private $_vars = array();
    private $_function;
    public static function factory(){
        return $test = new self(function() use(&$test){
            $string_set = 'This is a string';
            $test->bind('string', $string_set);
            return true;
        });
    }
    private function __construct($function){
        $this->_function = $function;
    }
    public function bind($key, &$var){
        $this->_vars[$key] = &$var;
        return $this;
    }
    public function fetch($key, &$var){
        $this->_vars[$key] = null;
        $var = &$this->_vars[$key]; // edited; was not assigning by reference
        return $this;
    }
    public function call(){
        return (bool) call_user_func($this->_function);
    }
}
$return = Test::factory()
    ->fetch('string', $string_get)
    ->call();
var_dump($return, $string_get);
// expected:  bool(TRUE), string(16) "This is a string"
// actual:    bool(TRUE), NULL

我在这里追逐雏菊,这可能吗?无论哪种方式,我都很感激并提前感谢你哪怕只是瞥了一眼这个问题,任何洞察力都是非常感谢的。

编辑:fetch() - $var = $this->_vars[$key];中的行没有通过引用分配数组元素。我现在已经编辑到$var = &$this->_vars[$key];,虽然它似乎没有效果。

奖励:如果这个问题是可以解决的,那显然是伟大的;我实际上希望bind()可以通过值来获取$var,而不是通过引用。方法签名将更改为类似set($key, $value)的内容。无论如何,再次感谢。


为了详细说明看似奇怪的(看着您的方向@Tomalak),我将提供更完整的类和使用场景:

class Action{
    private static $_cache = array();
    private static $_basePath;
    private $_vars = array();
    private $_function;
    public static function setBasePath($basePath){
        $basePath = rtrim($basePath, '/') . '/';
        if(!is_dir($basePath)){
            // throw exception, $basePath not found
        }
        self::$_basePath = $basePath;
    }
    public static function load($actionPath){
        $actionPath = self::$_basePath . $actionPath;
        if(array_key_exists($actionPath, self::$_cache)){
            return self::$_cache[$actionPath];
        }
        if(!is_file($actionPath)){
            // throw exception, $actionPath not found
        }
        $action = call_user_func(function() use(&$action, $actionPath){
            return require($actionPath);
        });
        if(!($action instanceof self)){
            // throw exception, $action of invalid type
        }
        self::$_cache[$actionPath] = $action;
        return $action;
    }
    public function __construct($function){
        if(!is_callable($function)){
            // throw exception, $function not callable
        }
        $this->_function = $function;
    }
    public function bindReturn($key, &$var){
        $this->_vars[$key] = &$var;
        return $this;
    }
    public function fetchInto($key, &$var){
        $this->_vars[$key] = null;
        $var = &$this->_vars[$key];
        return $this;
    }
    public function run(){
        return (bool) call_user_func_array($this->_function, func_get_args());
    }
}
############################################################################
// actions/test.php
return new Action(function($name)
    use(&$action){
        if($name == 'Alice'){
            return false;
        }
        $data = "Hi, my name is {$name}.";
        $action->bindReturn('data', $data);
        return true;
    });
############################################################################
// index.php (or whatever)
$result = Action::load('actions/test.php') // loaded
    ->fetchInto('data', $data)
    ->run('Alice');
// Failed
echo $result
    ? 'Success - ' . $data
    : 'Failed';
$result = Action::load('actions/test.php') // called from cache
    ->fetchInto('data', $data)
    ->run('Bob');
// Success - Hi, my name is Bob
echo $result
    ? 'Success - ' . $data
    : 'Failed';

您想要做的是根本不可能的(至少对于引用),因为您不能"重定向"引用。结果如下:

$instance->fetch('foo', $myVar);
public function fetch($key, &$var){
    // Here $var is a reference to $myVar.
    $var = &$this->_vars[$key]; // now $var is a reference to $this->_vars[$key]
                                // it is not connected to $myVar anymore.
}

你可以这样做:你可以向fetch()传递一个数组的引用,并将数组中的一个元素设置为对$this->_vars[$key]的引用,或者你可以向fetch()传递一个对象,并将成员变量设置为引用。


哦,对不起,我忽略了显而易见的一点:您当然可以在您所展示的用例中使用bindReturn()函数。

看起来你有问题

public function fetch($key, &$var){
    $this->_vars[$key] = null;
    $var = $this->_vars[$key];
    return $this;
}

如果你想删除键,不要将它设置为null,取消它:

编辑:修改代码以避免未初始化变量异常。

public function fetch($key, &$var){
    if(isset($this->_vars[$key]))
    {
        $var = $this->_vars[$key];
        unset($this->_vars[$key]);
    }
    else
    {
        $var = null;
    }
    return $this;
}