<?php
$a = new ArrayObject();
$a['b'] = array('c'=>array('d'));
print_r($a);
unset($a['b']['c']);
print_r($a);
ArrayObject Object
(
[b] => Array
(
[c] => Array
(
[0] => d
)
)
)
ArrayObject Object
(
[b] => Array
(
[c] => Array
(
[0] => d
)
)
)
您注意到即使在取消设置后$a['b']['c']
仍然存在。我希望$a
只剩下一个值(b
)。
在我的实际应用中,我收到以下警告:
间接修改MyClass的重载元素无效
MyClass
扩展ArrayObject
的位置。我有很多代码依赖于能够取消设置这样的嵌套元素,所以我怎样才能使它工作?
答案 0 :(得分:11)
一种方法
<?php
$a = new ArrayObject();
$a['b'] = array('c' => array('d'));
$d =& $a['b'];
unset($d['c']);
print_r($a['b']);
打印:
Array
(
)
为了解释为什么你最初使用的语法不会删除元素,我必须考虑更长的时间。
编辑:行为说明
正在发生的事情是对unset($a['b']['c']);
的调用被翻译成:
$temp = $a->offsetGet('b');
unset($temp['c']);
由于$temp
是$a
的副本而不是对它的引用,因此PHP在内部使用copy-on-write并创建第二个数组$temp
没有{{}} 1}},但['b']['c']
仍然可以。
另一个编辑:可重复使用的代码
所以,无论你采用哪种方式对其进行切片,似乎都要将$a
重载为function offsetGet($index)
导致麻烦;所以这里是我提出的最短的辅助方法,可以将它作为静态或实例方法添加到function &offsetGet($index)
的子类中,无论你的船是什么浮动:
ArrayObject
因此原始代码将成为
function unsetNested(ArrayObject $oArrayObject, $sIndex, $sNestedIndex)
{
if(!$oArrayObject->offSetExists($sIndex))
return;
$aValue =& $oArrayObject[$sIndex];
if(!array_key_exists($sNestedIndex, $aValue))
return;
unset($aValue[$sNestedIndex]);
}
YET另一个编辑:OO解决方案
好的 - 所以我今天早上一直在争抢b / c我在我的代码中发现了一个错误,经过修改后,我们可以基于OO实现一个解决方案。
只是你知道我试过了,扩展段错误..:
$a = new ArrayObject();
$a['b'] = array('c' => array('d'));
// instead of unset($a['b']['c']);
unsetNested($a, 'b', 'c');
print_r($a['b']);
另一方面,实现装饰器就像魅力一样:
/// XXX This does not work, posted for illustration only
class BadMoxuneArrayObject extends ArrayObject
{
public function &offsetGet($index)
{
$var =& $this[$index];
return $var;
}
}
现在这段代码可以正常运行:
class MoxuneArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable
{
private $_oArrayObject; // Decorated ArrayObject instance
public function __construct($mInput=null, $iFlags=0, $sIteratorClass='')
{
if($mInput === null)
$mInput = array();
if($sIteratorClass === '')
$this->_oArrayObject = new ArrayObject($mInput, $iFlags);
else
$this->_oArrayObject = new ArrayObject($mInput, $iFlags, $sIteratorClass);
}
// -----------------------------------------
// override offsetGet to return by reference
// -----------------------------------------
public function &offsetGet($index)
{
$var =& $this->_oArrayObject[$index];
return $var;
}
// ------------------------------------------------------------
// everything else is passed through to the wrapped ArrayObject
// ------------------------------------------------------------
public function append($value)
{
return $this->_oArrayObject->append($value);
}
public function asort()
{
return $this->_oArrayObject->asort();
}
public function count()
{
return $this->_oArrayObject->count();
}
public function exchangeArray($mInput)
{
return $this->_oArrayObject->exchangeArray($mInput);
}
public function getArrayCopy()
{
return $this->_oArrayObject->getArrayCopy();
}
public function getFlags()
{
return $this->_oArrayObject->getFlags();
}
public function getIterator()
{
return $this->_oArrayObject->getIterator();
}
public function getIteratorClass()
{
return $this->_oArrayObject->getIteratorClass();
}
public function ksort()
{
return $this->_oArrayObject->ksort();
}
public function natcassesort()
{
return $this->_oArrayObject->natcassesort();
}
public function offsetExists($index)
{
return $this->_oArrayObject->offsetExists($index);
}
public function offsetSet($index, $value)
{
return $this->_oArrayObject->offsetSet($index, $value);
}
public function offsetUnset($index)
{
return $this->_oArrayObject->offsetUnset($index);
}
public function serialize()
{
return $this->_oArrayObject->serialize();
}
public function setFlags($iFlags)
{
return $this->_oArrayObject->setFlags($iFlags);
}
public function setIteratorClass($iterator_class)
{
return $this->_oArrayObject->setIteratorClass($iterator_class);
}
public function uasort($cmp_function)
{
return $this->_oArrayObject->uasort($cmp_function);
}
public function uksort($cmp_function)
{
return $this->_oArrayObject->uksort($cmp_function);
}
public function unserialize($serialized)
{
return $this->_oArrayObject->unserialize($serialized);
}
}
仍然需要修改一些代码..;我没有看到任何方式。
答案 1 :(得分:4)
在我看来,ArrayObject
的“重载”括号运算符正在返回嵌套数组的副本,而不是对原始数据的引用。因此,当您调用$a['b']
时,您将获得ArrayObject
用于存储数据的内部数组的副本。进一步将其解析为$a['b']['c']
只是在副本中提供元素“c”,因此在其上调用unset()
并不会取消原始元素“c”。
ArrayObject
实现the ArrayAccess
interface,这实际上允许括号运算符处理对象。 ArrayAccess::offsetGet
的文档表明,从PHP 5.3.4开始,可以使用ArrayObject
运算符获取=&
内部数组中原始数据的引用,{{3}在他的例子中指出。
答案 2 :(得分:1)
您可以使用unset($a->b['c']);
代替unset($a['b']['c']);
,以防在项目中针对所有相同情况进行此类替换时不会出现大问题
答案 3 :(得分:0)
我似乎有partial solution。如果所有嵌套数组都是unset
的实例,则ArrayObject
似乎有效。为了确保所有嵌套数组都是ArrayObjects,我们可以从这个类派生出来:
class ArrayWrapper extends ArrayObject {
public function __construct($input=array(), $flags=ArrayObject::STD_PROP_LIST, $iterator_class='ArrayIterator') {
foreach($input as $key=>$value) {
if(is_array($value)) {
$input[$key] = new self($value, $flags, $iterator_class);
}
}
parent::__construct($input, $flags, $iterator_class);
}
public function offsetSet($offset, $value) {
parent::offsetSet($offset, is_array($value) ? new ArrayWrapper($value) : $value);
}
}
(针对递归更新;未经测试)
然后,只要您尝试添加嵌套数组,它就会自动转换为ArrayWrapper
。
不幸的是,许多其他数组函数(例如array_key_exists
)在ArrayObjects上不起作用。