【发布时间】: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