【问题标题】:PHP array references; holding references in an array for later usePHP 数组引用;将引用保存在数组中以供以后使用
【发布时间】:2011-10-26 00:28:50
【问题描述】:

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

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

例如,这是有效的:

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() 函数需要传递存储的匿名函数的返回值(否则我会将调用重新排序为@ 987654325@ 而不是 ->fetch()->call())

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

当匿名函数被调用时(fetch() 绑定完成后),它调用bind(),现在将$_vars 中的元素绑定到任何(@987654334 @ 包含 This is a string 在这种情况下)如果我的逻辑是正确的,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';

【问题讨论】:

  • 我不明白为什么fetch 需要将任何内容设置为空。也许我只是愚蠢。
  • @Tomalak Geret'kal - 否则索引不会初始化为任何内容,并且会引发通知,因为call()和后续函数)尚未绑定值到数组。
  • bind 发生在 call 下,它调用了一个传递给构造函数但没有立即调用的函数,这一事实完全让我感到困惑。解析起来非常复杂;必须有更好的方法来实现更广泛的目标。
  • @Tomalak Geret'kal - 不幸的是,没有更好的方法。我已经排除了大量与设置匿名函数等相关的逻辑,以隔离实际问题并使其更易于理解。实际上,我正在远离一种复杂的方法,转而支持这种方法。
  • 感谢@Tomalak Geret'kal - 正如海洋对泥土说的那样,我很欣赏沉积物 :P 真的,我很乐意得到一些反馈超出阿尔法。我很快就会在我的个人资料中进行链接,下次我们提出问题时,我会提及。

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


【解决方案1】:

您想要做的事情根本不可能(至少使用引用),因为您无法“重定向”引用。以下是发生的事情:

$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() 函数。这将毫无问题地工作。

【讨论】:

  • 感谢@Chronial - 感谢您的建议;所以没有办法将$myVar指向$this->_vars[$key]而不诉诸您建议的解决方法之一?另外,关于您对bindReturn() 的编辑,您究竟是什么意思?
  • 天哪,我猜你的意思是,但bindReturn() 正在做fetchInto() 应该做的工作。通过交换fetchInto() 引用赋值中的操作数,它可以工作。正如您的预编辑答案所解释的那样,我正在覆盖我的参考作业。我的,多么愚蠢的错误。再次感谢 Chronial!
  • 是的,这正是我的意思;)。只是出于好奇:bindReturn() 函数应该做什么?
  • bindReturn() 旨在将回调范围内的值绑定到外部变量。现在我已经稍微修改了我的设计,我意识到在任何情况下“绑定”要返回的值都不会提供任何优势,而简单地按值返回是最好的。此外,当通过引用绑定值时,始终需要中间变量,因此无法直接从函数调用返回值。稍后我会用更最终的版本更新我的答案。如果需要,请回来查看。再次感谢:)
【解决方案2】:

看来你有问题

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

如果要移除key,不要设置为null,取消设置:

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

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

【讨论】:

  • 删除了我的评论,因为我虽然误读了你的答案,但最终还是一样)谢谢@Dani - 不幸的是,这不起作用。设置 NULL 而不是 unset() 会执行双重任务,因为它会清空现有值或初始化数组元素。如果我使用unset(),则会收到关于未定义索引的通知,因为call() 尚未设置这些值。
  • @Bracketworks:设置为 null 不会清空现有变量。它将引用的变量设置为null,引用仍然有效。您可以尝试使用isset(我会尽快编辑答案)
  • 啊,好点子。然而,由于 fetch() 调用是在设置任何变量之前发生的,因此此时设置为 NULL 甚至不会影响被引用变量的值(尚未通过 bind() 引用任何内容
猜你喜欢
  • 1970-01-01
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多