ano*_*reh 16 php arrays interface multidimensional-array
我有一个类实现ArrayAccess,我试图让它与多维数组一起工作.exists和get工作.set并且unset给我一个问题.
class ArrayTest implements ArrayAccess {
private $_arr = array(
'test' => array(
'bar' => 1,
'baz' => 2
)
);
public function offsetExists($name) {
return isset($this->_arr[$name]);
}
public function offsetSet($name, $value) {
$this->_arr[$name] = $value;
}
public function offsetGet($name) {
return $this->_arr[$name];
}
public function offsetUnset($name) {
unset($this->_arr[$name]);
}
}
$arrTest = new ArrayTest();
isset($arrTest['test']['bar']); // Returns TRUE
echo $arrTest['test']['baz']; // Echo's 2
unset($arrTest['test']['bar']; // Error
$arrTest['test']['bar'] = 5; // Error
Run Code Online (Sandbox Code Playgroud)
我知道$_arr可以公开,所以你可以直接访问它,但对于我的实现,它是不希望的并且是私有的.
最后两行引发错误:Notice: Indirect modification of overloaded element.
我知道ArrayAccess通常不能使用多维数组,但无论如何围绕这个或任何有点干净的实现,将允许所需的功能?
我能想出使用字符作为分隔符,并在测试它的最好的想法set和unset和采取相应的行动.虽然如果你处理的是变深度,这真的很难实现.
有谁知道为什么exists和get工作,以便可能复制功能?
感谢任何人都能提供的帮助.
Ale*_*nov 19
可以通过更改public function offsetGet($name)为public function &offsetGet($name)(通过添加引用返回)来解决该问题,但它将导致致命错误(" ArrayTest :: offsetGet()的声明必须与ArrayAccess :: offsetGet()的声明兼容 ").
PHP作者不久前搞砸了这个类,现在他们不会为了向后兼容性而改变它:
我们发现,如果不破坏界面并创建BC或提供额外的界面来支持引用并因此创建内部噩梦,这是不可解决的 - 实际上我没有看到我们能够做到这一点的方式.因此,我们决定强制执行原始设计并禁止引用完整.
编辑:如果您还需要这个功能,我建议使用魔术方法,而不是(__get(),__set()等等),因为__get()按引用返回值.这会将语法更改为以下内容:
$arrTest->test['bar'] = 5;
Run Code Online (Sandbox Code Playgroud)
当然不是理想的解决方案,但我想不出更好的解决方案.
更新:此问题已在PHP 5.3.4中得到修复,ArrayAccess现在可以按预期工作:
从PHP 5.3.4开始,放松了原型检查,并且可以通过引用返回此方法的实现.这样就可以对ArrayAccess对象的重载数组维度进行间接修改.
这个问题实际上是可以解决的,完全是功能性的.
从这里对ArrayAccess文档的评论:
<?php
// sanity and error checking omitted for brevity
// note: it's a good idea to implement arrayaccess + countable + an
// iterator interface (like iteratoraggregate) as a triplet
class RecursiveArrayAccess implements ArrayAccess {
private $data = array();
// necessary for deep copies
public function __clone() {
foreach ($this->data as $key => $value) if ($value instanceof self) $this[$key] = clone $value;
}
public function __construct(array $data = array()) {
foreach ($data as $key => $value) $this[$key] = $value;
}
public function offsetSet($offset, $data) {
if (is_array($data)) $data = new self($data);
if ($offset === null) { // don't forget this!
$this->data[] = $data;
} else {
$this->data[$offset] = $data;
}
}
public function toArray() {
$data = $this->data;
foreach ($data as $key => $value) if ($value instanceof self) $data[$key] = $value->toArray();
return $data;
}
// as normal
public function offsetGet($offset) { return $this->data[$offset]; }
public function offsetExists($offset) { return isset($this->data[$offset]); }
public function offsetUnset($offset) { unset($this->data); }
}
$a = new RecursiveArrayAccess();
$a[0] = array(1=>"foo", 2=>array(3=>"bar", 4=>array(5=>"bz")));
// oops. typo
$a[0][2][4][5] = "baz";
//var_dump($a);
//var_dump($a->toArray());
// isset and unset work too
//var_dump(isset($a[0][2][4][5])); // equivalent to $a[0][2][4]->offsetExists(5)
//unset($a[0][2][4][5]); // equivalent to $a[0][2][4]->offsetUnset(5);
// if __clone wasn't implemented then cloning would produce a shallow copy, and
$b = clone $a;
$b[0][2][4][5] = "xyzzy";
// would affect $a's data too
//echo $a[0][2][4][5]; // still "baz"
?>
Run Code Online (Sandbox Code Playgroud)
然后,您可以扩展该类,如下所示:
<?php
class Example extends RecursiveArrayAccess {
function __construct($data = array()) {
parent::__construct($data);
}
}
$ex = new Example(array('foo' => array('bar' => 'baz')));
print_r($ex);
$ex['foo']['bar'] = 'pong';
print_r($ex);
?>
Run Code Online (Sandbox Code Playgroud)
这将为您提供一个可以像数组一样处理的对象(主要是参见代码中的注释),它支持多维数组set/get/unset.
| 归档时间: |
|
| 查看次数: |
4607 次 |
| 最近记录: |