Search code examples
phpsimplexml

Are SimpleXMLElement and SimpleXMLElement::children() the same thing?


Consider the following code:

<?php
$foo = new SimpleXmlElement(
'<foo>
    <bar>
        <baz id="b1"/>
        <baz id="b2"/>
        <baz id="b3"/>
    </bar>
</foo>
');
echo "<pre>";print_r($foo);echo "</pre><br/>";
echo "<pre>";print_r($foo->children());echo "</pre><br/>";
echo "foo===foo->children():".($foo===$foo->children()?"true":"false")."<br/>";//false
echo "foo==foo->children():".($foo==$foo->children()?"true":"false");//true

print_r shows the same content for foo and foo->children(). $foo==$foo->children() is true but $foo===$foo->children() is false. What the heck is $foo->children()?

The official document has a note that may be related to this question, but I cannot understand exactly its meaning.

Note: SimpleXML has made a rule of adding iterative properties to most methods. They cannot be viewed using var_dump() or anything else which can examine objects.


Solution

  • Despite its name, instances of the SimpleXMLElement class can represent a few different things:

    • A single XML element; in your example, $foo represents the <foo> element at the root of your XML document
    • A collection of XML elements with the same name; for instance, $foo->bar gives you an object with all child elements named bar
    • A collection of XML elements with different names, but the same parent; this is what ->children() gives you
    • A single XML attribute; $foo->bar[0]->baz[0]['id'] will give you an object for the id attribute of the first baz in your example
    • A collection of XML attributes on the same element; this is what ->attributes() gives you

    A lot of the time, you don't actually notice which of these you have, because various short-hands let you treat them interchangeably; for instance:

    • Property, method, and attribute calls on collections of elements and attributes generally refer to the first element in the collection. So $foo->bar->baz['id'] is the same as $foo->bar[0]->baz[0]['id']
    • Conversely, using a foreach loop with an object representing a single node automatically loops over the children of that element, as though you'd called ->children()

    There are however times when you need to tell the difference. For instance, foreach ( $foo->bar as $item ) will loop over all elements named bar; but foreach ( $foo->bar->children() as $item ) will access the first element named bar, and loop over its children.

    The children() method is also used to switch between namespaces, see Reference - How do I handle Namespaces (Tags and Attributes with a Colon in their Name) in SimpleXML?