首先,引用ArrayAccess::offsetSet()
上的'ole'手册:
此功能不是通过引用在作业中调用的,而是通过ArrayAccess重载的数组维度的间接更改(间接意义上它们不是通过直接更改维度,而是通过更改子维度或子-property或通过引用另一个变量分配数组维度。 而是调用ArrayAccess::offsetGet()。只有当该方法通过引用返回时,该操作才会成功,这只能从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);
好的,所以这不起作用。那么这本手册中的内容是指什么?
原因
我想允许通过数组运算符通过引用分配给实现ArrayAccess
的对象,如示例代码段所示。我之前已经对此进行了调查,我认为这不可能,但由于不确定性而又回到了这一点,我( re - )在手册中发现了这一点。现在我很困惑。
更新:当我点击发布您的问题时,我意识到这可能只是指通过引用指定给另一个变量,例如为$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);
就has
,get
,set
和remove
而言,它们对ArrayAccess
支持的方法没有任何问题。绑定功能是我不知所措的地方,我开始接受ArrayAccess和PHP的限制只是禁止它。
答案 0 :(得分:9)
手册所指的是所谓的“间接修改”。请考虑以下脚本:
$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)
的签名,但实际上这只是不可能。
顺便说一句,参考文献很难掌握。您将获得许多非显而易见的行为,对于数组项引用(尤其是那些具有一些特殊规则)尤其如此。我建议你完全避免它们。
答案 1 :(得分:3)
这不适用于ArrayAccess
,您可以添加一个公共函数,允许您设置对偏移量的引用(当然,这看起来与使用数组语法不同,所以这不是一个足够的答案) :
class Test implements ArrayAccess{
protected $_data = array();
public function &offsetGet($key){
return $this->_data[$key];
}
...
public function offsetSetReference($key, &$value)
{
$this->_data[$key] = &$value;
}
}
$test = new Test();
$test['foo'] = $var = 'bar';
$test->offsetSetReference('bar', $var);
$var = 'foo';
echo $test['bar']; # foo
$alias = &$test['bar'];
$alias = 'hello :)';
echo $var; # hello :)
首次实施ArrayAccess
时,可能忘记了这样的功能。
编辑:将其作为“参考作业”传递:
class ArrayAccessReferenceAssignment
{
private $reference;
public function __construct(&$reference)
{
$this->reference = &$reference;
}
public function &getReference()
{
$reference = &$this->reference;
return $reference;
}
}
class Test implements ArrayAccess{
...
public function offsetSet($key, $value){
if ($value instanceof ArrayAccessReferenceAssignment)
{
$this->offsetSetReference($key, $value->getReference());
}
else
{
$this->_data[$key] = $value;
}
}
然后,因为您实现了它,所以它可以完美运行。这可能比上面更明确的offsetSetReference
变体更好地接口:
$test = new Test();
$test['foo'] = $var = 'bar';
$test['bar'] = new ArrayAccessReferenceAssignment($var);
$var = 'foo';
echo $test['bar']; # foo
$alias = &$test['bar'];
$alias = 'hello :)';
echo $var; # hello :)