【问题标题】:How to remove recursion inside an object or array?如何删除对象或数组内的递归?
【发布时间】:2019-07-30 21:12:07
【问题描述】:

我有这个示例数组。

$data = new stdClass();

$data->foo = [
    'foo1' => &$data,
    'foo2' => 23,
];

$data->bar = new stdClass();

$data->nar->object = [
    'bar1' => &$data->bar,
    'bar2' => 43,
];

我想将其解析为:

$data = new stdClass();

$data->foo = [
    'foo1' => "RECURSION DETECTED",
    'foo2' => 23,
];

$data->bar = new stdClass();

$data->nar->object = [
    'bar1' => "RECURSION DETECTED",
    'bar2' => 43,
];

我需要它,因为json_encode 在检测到递归时无法编码数据。

我尝试了很多次,以不同的方式,我做了很多研究,但我没有找到任何真正帮助我的东西。

我最后一次尝试是:

function _stack(&$object, &$stack = [], $key = 'original')
{
    if (isObjectOrArray($object)) {
        if (!in_array($object, $stack, true)) {
            if (is_object($object)) {
                $stack[$key] = &$object;
            }
            foreach ($object as $key => &$value) {
                _stack($value, $stack, $key);
            }
        }
    }
    return $stack;
}

function _remove($object, $stack, $objectO = false, $key = 'original')
{
    /**
     * @var $objectO false | object
     */
    if (!$objectO) {
        $objectO = $object;
    }
    if (isObjectOrArray($object)) {
        foreach ($object as $prop => $value) {
            if (is_object($objectO)) {
                if (in_array($object->{$prop}, $stack, true) && $prop !== $key) {
                    $objectO->{$prop} = "RECURSION DETECTED";
                } else {
                    $objectO->{$prop} = _remove($object->{$prop}, $stack, $objectO->{$prop}, $prop);
                }
            } else {
                if (in_array($object[$prop], $stack, true) && $prop !== $key) {
                    $objectO[$prop] = "RECURSION DETECTED";
                } else {
                    $objectO[$prop] = _remove($object[$prop], $stack, $objectO[$prop], $prop);
                }
            }
        }
    }
    return $objectO;
}

首先我用原始对象(不是引用/指针)创建一个堆栈。 密钥以递归方式传递给函数,因此我确切地知道递归与原始对象的交汇点。我需要它,这样我就可以知道指针是什么以及原始对象是什么。

创建堆栈后,我运行相同的循环,但是 foreach 语句中的当前值是一个对象,并且他在堆栈中,并且当前键与传递给函数调用的当前键不同,引用/指针被破坏。

Array
(
    [foo1] => RECURSION DETECTED
    [foo2] => 23
)

但在所有函数调用结束时,我只得到:

RECURSION DETECTED

【问题讨论】:

    标签: php json parsing recursion


    【解决方案1】:

    我还在寻找另一种方式,因为这很有趣,但是很容易替换序列化字符串中的引用指针然后反序列化它:

    $data = unserialize(preg_replace('/R:\d+/', 's:18:"RECURSION DETECTED"', serialize($data)));
    

    PHP >= 7.3.0 的另一个选项是导出并强制它中断引用。 var_export 会抱怨递归,但它会很高兴地显示它,并将引用替换为 NULLvar_export 有第二个参数来返回输出而不是显示,但这不适用于递归,所以我缓冲并捕获了输出。

    ob_start();
    @var_export($data);
    $var = ob_get_clean();
    eval("\$data = $var;");
    

    对于 PHP __set_state 的类一起使用,而不是 stdClass

    class myClass {
    
        public static function __set_state($array) {
            $o = new self;
    
            foreach($array as $key => $val) {
                $o->$key = $val;
            }
            return $o;
        }
    }
    
    $data = new myClass();
    

    【讨论】:

    • 是的,它的工作原理,这很简单。我需要将R 替换为r
    • $data = unserialize(preg_replace('/R:\d+/', 's:18:"RECURSION DETECTED"', serialize($data))) 工作完美,但是,preg_replace 有什么意义,unserialize(serialize($data)) 也工作?
    猜你喜欢
    • 1970-01-01
    • 2021-07-15
    • 2016-06-19
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 2021-05-29
    • 1970-01-01
    • 2018-03-28
    相关资源
    最近更新 更多