Building infinite unordered HTML list using SPL

Iterating over a nested menu might be a bit cumbersome, especially when you want to get the values and show them respectively.

The problem that I want to solve here is to build an unordered HTML list that is based on an infinite nested array.

While it seems to be obvious to solve by writing a recursive function/method, but I was thinking for an alternative solution, a more simple and readable solution.

After a bit of reading, I came across the RecursiveIteratorIterator class, so let me show you how did I do that.

Here is the list that I have:

$products = [
  'Camera & Photo' => [
    'Video Projectors' => [],
    'Digital Cameras' => [
        'Digital SLRs' => [
            'Canon' => [
                'Canon EOS 4000D', 'Canon EOS 2000D DSLR'
            ],
            'Nikon' => [
                'Nikon D7500',
                'Nikon D5600'
            ],
            'Fujifilm' => [
                'Fujifilm X-A5 Mirrorless'
            ]
        ],
        'Mirrorless Cameras' => [
            'Sony' => [
                'Sony α6400 E-mount compact'
            ],
            'Panasonic' => [
                'Panasonic LUMIX DC-GH5LEB-K'
            ]
        ],
        'Lenses' => [
            'Camera Lenses' => [],
            'Camcorder Lenses' => [],
        ]
    ],
      'Mobile Phones' => [
          'Smart Phones' => [
              'Apple' => [
                  'iPhone 11',
                  'iPhone 11 Pro',
                  'iPhone Xs Max'
              ],
              'Samsung' => [],
              'Huawei' => [],
              'Google' => [],
          ]
      ]
  ]
];

First of all, I converted it to a RecursiveArrayIterator as follows:

$products = new RecursiveArrayIterator($products);

Then I created a new class in which it inherits from RecursiveIteratorIterator and I started overriding some methods of its method to show the <ul> and <li>:

class NestedList extends RecursiveIteratorIterator
{
    public function beginIteration()
    {
        echo "<ul>".PHP_EOL;
    }

    public function endIteration()
    {
        echo "</ul>".PHP_EOL;
    }

    public function beginChildren()
    {
        echo "<ul>".PHP_EOL;
    }

    public function endChildren()
    {
        echo "</ul></li>".PHP_EOL;
    }
}

As their names imply, these methods are used to react when a particular event occurs, for instance beginChildren will be invoked whenever the iterator encounters a child element, and so on.

$products = new NestedList($products, RecursiveIteratorIterator::SELF_FIRST);

foreach ($products as $category => $item) {
    if ($products->hasChildren()) {
        echo "<li>$category";
    } else {
        echo "<li>$item</li>\n";
    }
}

The RecursiveIteratorIterator::SELF_FIRST flag is used to show the parent as well as the children, if you try to remove this flag, then it’ll fall back to the LEAVES_ONLY (default) which means that it’ll only show the children.

Leave a Reply