PHP 数组引用;将引用保存在数组中以供以后使用
我试图保留变量引用以供以后使用。
不确定这是否可能,但我希望我可以初始化一个数组元素,并用变量引用它。然后,将所述数组元素的值设置为某个值,从而使该值可以从引用的变量访问。
例如,这是有效的:
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()
,现在绑定 < code>$_vars 到任何内容(在本例中包含 This is a string
的 $string_set
)如果我的逻辑是正确的, fetch()
绑定变量(本例中$string_get
)现在应该引用 $_vars
中的数组元素,该元素引用 $string_set
包含这是一个字符串
。
但似乎并非如此。这是失败的代码(为了简洁而精简,但所有重要部分都在那里)
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];
,尽管它看起来没有效果。
奖励< /strong>:如果这个问题可以解决,那就太好了;我实际上希望 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';
I'm trying to hold onto a variable reference for later use.
Not certain this is even possible, but I'm hoping I can initialize an array element, and reference it with a variable. Then, set the value of said array element to something, therefore making the value accessible from the referenced variable.
For example, this works:
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"
Now here's the problem; the ordering of method calls. I can't have the call()
function returning a reference to $this
, as the call()
function needs to pass up the return value of the stored anonymous function (otherwise I'd reorder the calls to be ->call()->fetch()
instead of ->fetch()->call()
)
Anyways, the fetch()
method should be setting the appropriate element by key in $_vars
to NULL
(to empty any existing value, or initialize it, whichever) and then referencing that element to the passed $var
.
When the anonymous function is called (after the fetch()
binding is done), it calls bind()
, now binding the element in $_vars
to whatever (a $string_set
containing This is a string
in this case) If my logic is correct, the fetch()
bound variable ($string_get
in this case) should now reference the array element in $_vars
which is referencing $string_set
which contains This is a string
.
Doesn't seem that way though. Here's the code that's failing (stripped down for brevity, but all the important parts are there)
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
Am I chasing daisies here, is this even possible? Either way, I appreciate and thank you in advance for even glancing at this problem, any insight is really appreciated.
Edit: the line in fetch()
- $var = $this->_vars[$key];
wasn't assigning the array element by reference. I've edited it now to $var = &$this->_vars[$key];
, though it seemingly has no effect.
Bonus: If this problem is solvable, that's obviously great; I'm actually hoping that bind()
can take $var
by value, rather than by reference. The method signature would be changed to something like set($key, $value)
. Anyways, thanks again in advance.
To elaborate for the seemingly curious (looking in your direction @Tomalak) I'll provide the more complete class, and usage scenario:
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';
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您想要做的事情根本不可能(至少对于引用而言),因为您无法“重定向”引用。发生的情况如下:
您可以执行以下操作:您可以传递
fetch()
对数组的引用,并将该数组中的一个元素设置为对$this->_vars[ 的引用$key]
或者您可以传递fetch()
一个对象并设置一个成员变量作为引用。哦,抱歉,错过了显而易见的事情:您当然可以在您提出的用例中使用
bindReturn()
函数。那会毫无问题地工作。What you want do is simply not possible (at least with referencces), because you cannot "redirect" a reference. Here's what happens:
Here's what you can do: You can pass
fetch()
a reference to an array and set an element in that array to be a reference to$this->_vars[$key]
or you can passfetch()
an object and set a member variable to be the reference.Oh, sry missed the obvious: You can of course just use your
bindReturn()
function in the use-case you presented. That would work without problems.看起来你有问题
如果你想删除键,不要将其设置为空,取消设置它:
编辑:更改代码以避免未初始化的变量异常。
Looks like you have problem with
If you want to remove the key, don't set it to null, unset it:
Edit: changed the code to avoid uninitialized variable exception.