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

发布于 2024-11-29 10:56:45 字数 5421 浏览 0 评论 0原文

我试图保留变量引用以供以后使用。

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

例如,这是有效的:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独行侠 2024-12-06 10:56:45

您想要做的事情根本不可能(至少对于引用而言),因为您无法“重定向”引用。发生的情况如下:

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

What you want do is simply not possible (at least with referencces), because you cannot "redirect" a reference. Here's what happens:

$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.
}

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 pass fetch() 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.

久隐师 2024-12-06 10:56:45

看起来你有问题

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

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

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

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

Looks like you have problem with

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

If you want to remove the key, don't set it to null, unset it:

Edit: changed the code to avoid uninitialized variable exception.

public function fetch($key, &$var){
    if(isset($this->_vars[$key]))
    {
        $var = $this->_vars[$key];
        unset($this->_vars[$key]);
    }
    else
    {
        $var = null;
    }
    return $this;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文