dutja92
dutja92

Reputation: 13

Why does PHP treats this DOM object like an array?

I'm following this tutorial:

https://www.w3schools.com/php/php_xml_dom.asp

Looping through XML part is problematic. PHP for some reason treats DOM object as an array. Furthermore, var_dump returns nothing about object attributes except length, but program output looks like it came out of nowhere. Can foreach loop through object somehow ? And if it does, where are these attributes contained (node name and node value) because var_dump is not showing them ?

$xml=new DOMDocument ();
$xml->load('note.xml');

$array_of_nodes=$xml->documentElement->childNodes;

var_dump($array_of_nodes);

foreach($array_of_nodes as $item) {
    echo $item->nodeName."  ".$item->nodeValue."<br>";
}

Var dump function returns this:

object(DOMNodeList)#3 (1) { ["length"]=> int(9) } #text

But the executed code look like this:

text =

to = Tove

text =

from = Jani

text =

heading = Reminder

text =

body = Don't forget me this weekend!

text =

Upvotes: 1

Views: 430

Answers (2)

Seviel
Seviel

Reputation: 83

childNodes is a property of DOMNodeList type. The reason why var_dump doesn't show anything about it is simply because var_dump shows only those class properties that have been declared by their developers by calling such C-functions as

ZEND_API int zend_declare_property(...)
ZEND_API int zend_declare_property_null(...)
ZEND_API int zend_declare_property_bool(...)
ZEND_API int zend_declare_property_long(...)
ZEND_API int zend_declare_property_double(...)
ZEND_API int zend_declare_property_string(...)
ZEND_API int zend_declare_property_stringl(...)

Source: answer by akond: Why doesn't var_dump work with DomDocument objects, while print($dom->saveHTML()) does?

That is, developers of DOM extension chose not to expose the structure of DOMNodeList class.

The reason why you can iterate through DOMNodeList is because it implements Traversable interface which signals that the class can be iterated through by using foreach.

Upvotes: 1

ThW
ThW

Reputation: 19502

DOMNodeList implements several interfaces: Traversable, ArrayAccess and Countable. This allows using generic syntax to access the node objects in the list. Without them you would need to use specific methods and properties like this:

for ($i = 0; $c = $nodeList->length; $i < $c; $i++) {
  $node = $nodeList->item($i);
  //...
}

Traversable allows you to use foreach.

foreach ($nodeList as $node) {
  //...
}

ArrayAccess allows you use array syntax to access nodes by index, it replaces the ->item(...) calls with [...].

if (isset($nodeList[0])) {
  $node = $nodeList[0];
  //...
}

Countable allows you use count($nodeList) instead of $nodeList->length.

Traversable has the most visual impact. It greatly reduces the complexity of the call. But that is only the first benefit. You can validate against the interfaces using typehints or instanceof. This decouples you code, making it more robust and reusable.

However looping trough DOM is a lot easier if you use Xpath expressions. If you used CSS selectors before, you can think of Xpath expressions as a more powerful sibling.

$document = new DOMDocument();
$document->load('note.xml');
$xpath = DOMXpath($document);

foreach($xpath->evaluate('/note') as $item) {
    echo 'To: ', $xpath->evaluate('string(to)', $item), "\n";
    echo 'From: ', $xpath->evaluate('string(from)', $item), "\n";
    echo 'Title: ', $xpath->evaluate('string(heading)', $item), "\n";
    echo 'Text: ', $xpath->evaluate('string(body)', $item), "\n";
}

Upvotes: 1

Related Questions