php - 如何使用 ArrayObject 取消设置嵌套数组?

标签 php arrayobject

ideone

示例代码:

<?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)。

在我的实际应用中,我收到以下警告:

Indirect modification of overloaded element of MyClass has no effect

其中 MyClass 扩展了 ArrayObject。我有很多代码依赖于能够像这样取消设置嵌套元素,那么我怎样才能让它工作?

最佳答案

一种方法

<?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 在内部使用写时复制并创建第二个数组,其中 $temp 没有 ['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]);
}

所以原来的代码会变成

$a      = new ArrayObject();
$a['b'] = array('c' => array('d'));

// instead of unset($a['b']['c']);
unsetNested($a, 'b', 'c');
print_r($a['b']);

另一个编辑:面向对象的解决方案

好的 - 所以今天早上我一定是手忙脚乱,因为我发现我的代码中有错误,修改后,我们可以基于 OO 实现解决方案。

只是想让你知道我试过了,扩展段错误..:

/// 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);
    }
}

现在这段代码可以正常工作了:

$a      = new MoxuneArrayObject();
$a['b'] = array('c' => array('d'));
unset($a['b']['c']);
var_dump($a);

不过还是要修改一些代码..;我看不出有什么办法解决这个问题。

关于php - 如何使用 ArrayObject 取消设置嵌套数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9981884/

相关文章:

php - WordPress URL 更改失败

javascript - 按第二个日期属性减少具有重复 ID 的对象数组

php - 何时适合使用 ArrayObject 而不是 Array

java - 如何将对象添加到 JSONArray

php - 如果项不在数组中,则无法扩展 ArrayObject::offsetGet() 函数以返回 null

java - 如何对对象数组的特定元素进行排序

javascript - 将变量值从一个函数传递到另一个函数

php - 将关联的 PHP 数组插入 mysql 而无需键入每个单独的插入名称和值

php - 根据预订系统中的可用房间打印 HTML 表格

php - 将 PHP 部署到 Azure 网站