2

I'm currently rewriting a navigation structure to be sorted by size into multiple columns, when I encountered some unexpected behavior, which I've successfully recreated here.

I'm creating an array with several items, also arrays. the items contain a name and might contain an array sub which is an array of more items. This has the possibility to be nested into infinity. The list will be displayed in HTML as a multiple layered ul. Using a recusive function would make sense in this case. As mentioned before the list will be sorted by size later on, for that reason I created the variable $index which is supposed to count the total amount of items in the current list, but instead of continuing to count after one level is completed PHP decides to use the previous iteration before the function was opened recusively.

Code, Output and expexted output below.

My Question: Is there a way to iterate the variable $index through the whole function?

PHP Code:

<!-- language: php -->
<?php
$lists = [
    [
        'name' => 'level0-item',
        'sub' => [
            ['name' => 'level1-item'],
            ['name' => 'level1-item'],
            ['name' => 'level1-item'],
            [
                'name' => 'level1-item',
                'sub' => [
                    ['name' => 'level2-item'],
                    ['name' => 'level2-item'],
                ]
            ],
            [
                'name' => 'level1-item',
                'sub' => [
                    ['name' => 'level2-item'],
                    ['name' => 'level2-item'],
                ]
            ],
        ]
    ],

    [
        'name' => 'level0-item',
        'sub' => [
            ['name' => 'level1-item'],
            ['name' => 'level1-item'],
            ['name' => 'level1-item'],
        ]
    ]
];

function handleLists($lists, $index = 0, $level = 0) {
    echo '<ul>';
    foreach ($lists as $list) {
        echo '<li>';
        $index++; // increas index
        echo $list['name'] . ' - level: ' . $level . ' - index: ' . $index;

        if ($list['sub'])
            handleLists($list['sub'], $index, $level+1); // recursive call
        echo '</li>';
    }
    echo '</ul>';
}

handleLists($lists);
?>

Output:

  • level0-item - level: 0 - index: 1
    • level1-item - level: 1 - index: 2
    • level1-item - level: 1 - index: 3
    • level1-item - level: 1 - index: 4
    • level1-item - level: 1 - index: 5
      • level2-item - level: 2 - index: 6
      • level2-item - level: 2 - index: 7
    • level1-item - level: 1 - index: 6
      • level2-item - level: 2 - index: 7
      • level2-item - level: 2 - index: 8
  • level0-item - level: 0 - index: 2
    • level1-item - level: 1 - index: 3
    • level1-item - level: 1 - index: 4
    • level1-item - level: 1 - index: 5

Expected output:

  • level0-item - level: 0 - index: 1
    • level1-item - level: 1 - index: 2
    • level1-item - level: 1 - index: 3
    • level1-item - level: 1 - index: 4
    • level1-item - level: 1 - index: 5
      • level2-item - level: 2 - index: 6
      • level2-item - level: 2 - index: 7
    • level1-item - level: 1 - index: 8
      • level2-item - level: 2 - index: 9
      • level2-item - level: 2 - index: 10
  • level0-item - level: 0 - index: 11
    • level1-item - level: 1 - index: 12
    • level1-item - level: 1 - index: 13
    • level1-item - level: 1 - index: 14

Addition

I could have understood nested foreach-/for-loops incorrectly, here is some hopefully understandable pseudocode, i gets increased by 1 every time a new foreach opens.

Expected behavior:

i = 0

// step 1
foreach1 opens i = 1

// step 2
foreach1
__foreach2 opens i = 2

// step 3
foreach1
__foreach2
foreach1 opens i = 3

// step 4
foreach1
__foreach2
foreach1
__foreach2 opens i = 4

Apparent behavior:

i = 0

// step 1
foreach1 opens i = 1

// step 2
foreach1
foreach1 opens i = 2

// step 3
foreach1
__foreach2 opens i = 2 (cause previous foreach1 i = 1)
foreach1

// step 4
foreach1
__foreach2
foreach1
__foreach2 opens i = 3 (cause previous foreach1 i = 2)

3
  • Your question and example is to hard to understand. Can you make a smaller example? To me your output is the same as the expected output. See stackoverflow.com/help/mcve Commented Mar 24, 2018 at 14:12
  • Did my answer help you? Commented Mar 25, 2018 at 10:49
  • @Andreas Actually I've reduced my code quite a bit to be easily understandable. But I've highlighted the differences in the output. Commented Mar 25, 2018 at 17:22

1 Answer 1

2

When you want to keep track of the actual value of $index throughout the whole tree then you could pass it over to handleLists as reference (&index) instead of a value:

function handleLists($lists, &$index = 0, $level = 0) { 
....
}

In this way when you are within a recursive call (level 1) and increment $index, then this index is also incremented on the first level (level 0) because it's the same variable when you enter a deeper level.

Hope this helps.

Sign up to request clarification or add additional context in comments.

1 Comment

As far as this does work in the simplified PHP example, I haven't found a way to make this work in a Smarty Template I'm extending, if there are no better answers popping up soon I'll definitely accept your answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.