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

时间:2011-08-12 17:30:22

标签: php arrays reference pass-by-reference method-chaining

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

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

例如,这有效:

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()方法应该在$_varsNULL中按键设置相应的元素(清空任何现有值,或者初始化它,无论哪个)然后将该元素引用到传递的$var

当调用匿名函数(<{>> fetch()绑定完成之后)时,它会调用bind(),现在将$_vars中的元素绑定到任何内容( 一个$string_set在这种情况下包含This is a string )如果我的逻辑是正确的,那么fetch()绑定变量(在这种情况下为 $string_get < / em>)现在应引用$_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';

2 个答案:

答案 0 :(得分:2)

看起来你有问题

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

答案 1 :(得分:2)

您想要做的事情根本不可能(至少在参考时),因为您无法“重定向”参考。这是发生的事情:

$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()个对象并将成员变量设置为参考。


哦,sry错过了显而易见的事实:您当然可以在您提供的用例中使用bindReturn()函数。这没有问题。