PHP 递归:展平树,保留元数据

PHP Recursion: Flatten Tree, Preserve Metadata

想象一下,您有一棵树代表一个您希望保留在表中但保留嵌套级别的家族。我想将下面的 post 数据放入下面的结构中。

我相信 RecursiveIterator 可能是执行此操作的方法,但我不确定我将如何操作。我有适用于大多数情况的代码,但它已经变得丑陋、臃肿。如果你愿意,我可以 post。

stdClass Object
(
    [name] => Smith
    [type] => Family
    [children] => Array(
            [1] => stdClass Object
                (
                    [name] => Michael
                    [type] => Uncle
                    [children] => Array(
                            [0] => stdClass Object
                                (
                                    [name] => Jared
                                    [type] => cousin
                                )
                        )
                )
            [2] => stdClass Object
                (
                    [name] => Jeff
                    [type] => Dad
                    [children] => Array(
                            [0] => stdClass Object
                                (
                                    [name] => Jonas
                                    [type] => self
                                )
                            [1] => stdClass Object
                                (
                                    [name] => Leah
                                    [type] => sister
                                    [children] => Array(
                                            [0] => stdClass Object
                                                (
                                                    [name] => Jacob
                                                    [type] => nephew
                                                )
                                        )
                                )
                        )
                )
        )
)

持久化的记录应该是这样的:

Array
(
    stdClass Object ( [name] => Smith [type] => Family [subgroup] => 0 [parent_subgroup] => )
    stdClass Object ( [name] => Michael [type] => Uncle [subgroup] => 1 [parent_subgroup] => 0 )
    stdClass Object ( [name] => Jared [type] => Cousin [subgroup] => 2 [parent_subgroup] => 1 )
    stdClass Object ( [name] => Jeff [type] => Dad [subgroup] => 1 [parent_subgroup] => 0 )
    stdClass Object ( [name] => Jonas [type] => self [subgroup] => 3 [parent_subgroup] => 1 )
    stdClass Object ( [name] => Leah [type] => sister [subgroup] => 3 [parent_subgroup] => 1 )
    stdClass Object ( [name] => Jacob [type] => nephew [subgroup] => 4 [parent_subgroup] => 3 )     
)

P.S。不,我和我姐姐没有孩子。那只是我的类比。 ;)

RecursiveIterator classes 可能会有点乱,我喜欢尽量保持简单。您可以使用 RecursiveIteratorIterator 遍历迭代器的值,它甚至可以为您提供当前深度(或 subgroup 在您的情况下)。

这里的挑战是父级不是数组,但我们可以在构造函数中处理它。

<?php
class FamilyIterator implements RecursiveIterator{
    private $data, $counter;

    public function __construct($familyTree){
        $this->data = is_array($familyTree) ? $familyTree : [$familyTree];
    }

    public function current(){
        $row = $this->data[$this->counter];
        return (object)[
            'name' => $row->name,
            'type' => $row->type
        ];
    }

    public function key(){
        return $this->counter;
    }

    public function next(){
        $this->counter++;
    }

    public function rewind(){
        $this->counter = 0;
    }

    public function valid(){
        return $this->counter < count($this->data);
    }

    public function hasChildren(){
        $row = $this->data[$this->counter];
        return isset($row->children);
    }

    public function getChildren(){
        $row = $this->data[$this->counter];
        return new self($row->children);
    }
}

然后你可以像这样使用这个class:

$loop = new RecursiveIteratorIterator(
    new FamilyIterator($dataObj),
    RecursiveIteratorIterator::SELF_FIRST
);

当您 foreach 超过 $loop 时,它会在需要时自动调用 getChildren 方法,因此在 foreach 中您将拥有每一行。你甚至可以问 RecursiveIteratorIterator 深度。

$newData = [];
foreach($loop as $row){
    $row->subgroup = $loop->getDepth();
    $newData[] = $row;
}

演示:https://eval.in/444078

这可能不完全您想要的,但希望它能为您指明正确的方向。 RecursiveIterator不需要太复杂。