← Back to blog

Building infinite unordered HTML list using SPL

| PHP

This article was published over 2 years ago. Some information may be outdated.

Iterating over a nested menu is not easy, especially when the menu has many nested levels.

The problem to solve here is building an unordered HTML list based on a multi-level nested menu for products:

$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' => [],
          ]
      ]
  ]
];

The SPL library solves this problem cleanly.

SPL provides a set of iterators. This post uses RecursiveArrayIterator and RecursiveIteratorIterator.

As its name implies, RecursiveArrayIterator iterates over a given array, but it does not support nested arrays on its own. That is why you also need RecursiveIteratorIterator.

First, wrap the array:

$products = new RecursiveArrayIterator($products);

The RecursiveIteratorIterator class has four methods that fire when specific events occur: beginIteration, endIteration, beginChildren, and endChildren.

Here is a class that uses these four methods:

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

Now use the class:

$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 shows the parent and its children. Without this flag, it falls back to LEAVES_ONLY (the default), which means only the leaf nodes are shown.

Here is the final result:

Unordered list

Summary

  • RecursiveArrayIterator -- iterates over arrays but does not handle nesting on its own; it must be combined with RecursiveIteratorIterator.
  • Event methods -- beginIteration, endIteration, beginChildren, and endChildren give you precise control over the HTML output at each nesting level.
  • SELF_FIRST flag -- required to include parent nodes in the output; without it, only leaf nodes appear.
  • SPL for nested structures -- a clean, built-in solution that handles arbitrary nesting depth without manual recursion.
Share