ATTENTION: You are viewing a page formatted for mobile devices; to view the full web page, click HERE.

Other Software > Developer's Corner

PHP5 driving me insane! removeChild() bug?

(1/1)

Ampa:
1st: I am NOT a PHP expert. I struggle. I read a lot of help and tutorials. I understand some of them!

2nd: I found a PHP driven menu system called EasyNav - that was the easy bit.. things go downhill from this point!

I like the way that PHP is used to rewrite the site navigation, specifically removing nested menu items, and applying ID and CLASS tags to the menu to facilitate easy styling.

BUT the original script is written for PHP4 and my host uses PHP5. No problem, I thought, I'll rewrite the bits of the script that I need, and learn a lot about PHP along the way.

Generally I have got things working, but there is a bug in the code somewhere...

In one section I loop through all the UL elements in the DOM, checking to see whether their parent nodes are LI elements. If they are then the UL is a nested list, and so, unless it is the one containing the current page, should be removed from the menu.


--- Code: PHP ---$HTMLDOM = new DOMDocument();                           //Create a new DOMDocument.$HTMLDOM->loadHTML($NavHTML);                           //Convert $NavHTML to a tree of DOM objects.$ULs = $HTMLDOM->getElementsByTagname("ul");            //Get a NodeList of the <ul> elements in the document.foreach($ULs as $CurrentUL)                                     //For each <ul>...{        $ULParent=$CurrentUL->parentNode;                       //Get its parent.        if ($ULParent->nodeName=='li')                          //If parent is an <li>, then this is a nested list...        {                if($ULParent->getElementsByTagName('strong')->item(0)==NULL)    //If the nested list does NOT contain current page.                {                        $ULParent->removeChild($CurrentUL);     //Remove the child node. (ie the nested list).                }        }}
To test it I run the loop on the following navigation structure...


--- Code: HTML ---<ul id="NavRoot">  <li><a href="index.php">A no_kids</a></li>  <li><a href="B.php">B 2_kids</a>    <ul id="Bsub">      <li><a href="B1.php">B.1</a></li>          <li><a href="B2.php">B.2</a></li>        </ul>  </li>  <li><a href="C.php">C 2_kids</a>    <ul id="Csub">      <li><a href="C1.php">C.1</a></li>          <li><a href="C2.php">C.2</a></li>        </ul>  </li>  <li><a href="D.php">D 2_kids</a>    <ul id="Dsub">      <li><a href="D1.php">D.1</a></li>          <li><a href="D2.php">D.2</a></li>        </ul>  </li>  <li><a href="E.php">E no_kids</a></li></ul>
The current page is index.php, so ALL the sub-menus should be removed; but the actual output is...

A no_kids
B 2_kids
C 2_kids
C.1
C.2
D 2_kids
E no_kids

ie. sub-menus B and D are removed but C is not!

If I watch what is happening in the code, the foreach loop skips the iteration for C. If I comment out the removeNode() command, then the loop works correctly.

Does anyone have any idea why the removeNode() command is causing my loop to jump?

f0dder:
Hm, perhaps something along the lines of iterator invalidation - I don't know what PHP does, but at least in C++ when you're iterating over container elements, for most container types it's unsafe to remove items from the container. Probably not the problem here, but if it is the problem, you'll probably end up having to restructure the code; instead of removing items from the actual list, change it so you build a copy (excluding the items you don't want), and then "activate" that copy...

Ampa:
Thanks F0dder, I think you are right...

When I remove the child node, the length of the FOREACH loop changes, so I need to replace it with a standard FOR loop, and decrement the loop counter if a node is removed.

UPDATE: Tried it. It works :)

Thanks again

Navigation

[0] Message Index

Go to full version