php - PHP 中的 ArrayAccess——通过引用分配给偏移量

标签 php arrays reference arrayaccess

首先,引用关于 ArrayAccess::offsetSet() 的 ole' 手册:

This function is not called in assignments by reference and otherwise indirect changes to array dimensions overloaded with ArrayAccess (indirect in the sense they are made not by changing the dimension directly, but by changing a sub-dimension or sub-property or assigning the array dimension by reference to another variable). Instead, ArrayAccess::offsetGet() is called. The operation will only be successful if that method returns by reference, which is only possible since PHP 5.3.4.

我对此有点困惑。这似乎表明(从 5.3.4 开始)可以定义 offsetGet() 以在实现类中通过引用返回,从而通过引用处理赋值。

所以,现在是一个测试片段:

(忽略缺少验证和 isset() 检查)

class Test implements ArrayAccess
{
    protected $data = array();

    public function &offsetGet($key)
    {
        return $this->data[$key];
    }

    public function offsetSet($key, $value)
    {
        $this->data[$key] = $value;
    }

    public function offsetExists($key) { /* ... */ }

    public function offsetUnset($key) { /* ... */ }

}

$test = new Test();

$test['foo'] = 'bar';
$test['foo'] = &$bar; // Fatal error: Cannot assign by reference to
                      // overloaded object in

var_dump($test, $bar);    

好吧,那是行不通的。那这个说明书指的是什么呢?

Reason
I'd like to permit assignment by reference via the array operator to an object implementing ArrayAccess, as the example snippet shows. I've investigated this before, and I didn't think it was possible, but having come back to this due to uncertainty, I (re-)discovered this mention in the manual. Now I'm just confused.


更新:当我点击发布您的问题时,我意识到这可能只是指通过引用到另一个变量的赋值,例如作为 $bar = &$test['foo'];。如果是这样,那么道歉;尽管知道如何(如果可能的话)通过对重载对象的引用进行分配会很棒。


进一步阐述:归根结底,我想要以下方法别名:

isset($obj[$key]);       // $obj->has_data($key);

$value = $obj[$key];     // $obj->get_data($key);

$obj[$key] = $value;     // $obj->set_data($key, $value);

$obj[$key] = &$variable; // $obj->bind_data($key, $variable);

// also, flipping the operands is a syntactic alternative
$variable = &$obj[$key]; // $obj->bind_data($key, $variable);

unset($obj[$key]);       // $obj->remove_data($key);

hasgetsetremove 而言,它们没有问题ArrayAccess 支持的方法。绑定(bind)功能是我不知所措的地方,并且我开始接受 ArrayAccess 和 PHP 的局限性完全禁止这样做。

最佳答案

手册所指的是所谓的“间接修改”。考虑以下脚本:

$array = new ArrayObject;
$array['foo'] = array();
$array['foo']['bar'] = 'foobar';

在上面的脚本中,$array['foo'] = array(); 会触发一个offsetSet('foo', array())$array['foo']['bar'] = 'foobar'; 另一方面会触发 offsetGet('foo')。为什么这样?最后一行将在引擎盖下大致像这样评估:

$tmp =& $array['foo'];
$tmp['bar'] = 'foobar';

所以$array['foo']首先被ref获取,然后被修改。如果您的 offsetGet 通过 ref 返回,这将成功。否则你会得到一些间接修改错误。


另一方面,您想要的恰恰相反:不是通过引用获取值,而是分配它。这理论上需要offsetSet($key, &$value)的签名,但实际上这不可能

顺便说一句,引用很难掌握。你会得到很多不明显的行为,对于数组项引用尤其如此(它们有一些特殊规则)。我建议您完全避免使用它们。

关于php - PHP 中的 ArrayAccess——通过引用分配给偏移量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8685186/

相关文章:

php - 在 Doctrine/Symfony 3 中创建类似 SQL 触发器的东西

php - Symfony php zip 文件下载时有零字节

php - 允许查看个人资料页面(所有人)

c++ - 动态二维数组非连续内存 C++

struct - 引用子结构数组的 Golang 问题

php - 具有固定参数值的路由的别名

c# - 搜索 int[] 列表以查找匹配的 int[]

arrays - 打印数组只导致第一个值被打印到excel中?

C++ 重载 << 和一元负号

python - Python 函数列表