Skip to content
Advertisement

How to recursively iterate object?

I have instance of this class, which contains an array of several instances of this class. And each of which can contain instances of this class, etc. This class implements the tree model.

class Node implements Arrayable, Iterator, Jsonable, JsonSerializable, Countable, ArrayAccess 
{
    /**
     * @var Node[] 
     */
    protected $childs = [];

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

    /*
     * @var Node $node 
     */
    public function add(Node $node)
    {
       $this->childs[] = $node;
    }

    ...
       Here implementation of Interaces
    ...
}

I want get all objects model as array structure for JSON representation in future. For that I need recursive iterate all object structure. I can do it simple foreach function with recursive call interate function, but I like to use PHP Interator interfaces, which provides this functional.

How I can do it?

I tried this code, but it didn’t work:

//    $this->tree is instance of Node class 

$iterator = new RecursiveArrayIterator($this->tree);
$iterator = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST );

foreach($this->tree as $key => $node) {

}

Advertisement

Answer

I’m still not quite sure what you’re trying to do, but here are some examples which might help you (full code below):


Implementing JsonSerializable:

When implementing this interface you’ll be able to control what data will be serialized when json_encode is used on any instance of the class:

<?php
class Node implements JsonSerializable
{
    // ...

    /**
     * @inheritdoc
     */
    public function jsonSerialize()
    {
        return [
            'data' => $this->data,
            'children' => $this->children
        ];
    }
}

// ...

print_r(json_encode($root, JSON_PRETTY_PRINT));

Extending RecursiveArrayIterator:

For this to work you only need to extend RecursiveArrayIterator and implement the required methods to work with your Node class:

<?php
class NodeIterator extends RecursiveArrayIterator
{
    /**
     * @inheritdoc
     */
    public function hasChildren()
    {
        return $this->current()->hasChildren();
    }

    /**
     * @inheritdoc
     */
    public function getChildren()
    {
        return new NodeIterator($this->current()->getChildren());
    }
}

// ...

$it = new RecursiveIteratorIterator(
    new NodeIterator([$root]),
    RecursiveIteratorIterator::SELF_FIRST
);

Extending RecursiveArrayIterator while implementing IteratorAggregate:

An extension to the above could be to also implement IteratorAggregate on Node

<?php
class Node implements IteratorAggregate
{
    // ...

    /**
     * @inheritdoc
     */
    public function getIterator()
    {
        return new NodeIterator([$this]);
    }
}

// ...

$it = new RecursiveIteratorIterator($root, RecursiveIteratorIterator::SELF_FIRST);

Demo: https://3v4l.org/D0GfX

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement