Weird behaviour in SimpleXMLElement Object when printing the array

254 views Asked by At

I'm struggling with an array in my SimpleXMLElement Object. Somehow I don't get the expected result when I print the array $node->reference.

print_r($node); shows:

SimpleXMLElement Object
(
    [reference] => Array
        (
            [0] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [resourceIdentifier] => 52chgb7f-1a00-4eaf-ac8a-5d4557f9796a
                        )

                )

            [1] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [resourceIdentifier] => 52cbccc3-b754-4e88-9238-5d5257f9796a
                        )

                )

        )
)

But print_r($node->reference); and print_r($node->reference->children()); shows:

SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [resourceIdentifier] => 52chgb7f-1a00-4eaf-ac8a-5d4557f9796a
        )

)

I expect to see:

Array
(
    [0] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [resourceIdentifier] => 52chgb7f-1a00-4eaf-ac8a-5d4557f9796a
                )

        )

    [1] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [resourceIdentifier] => 52cbccc3-b754-4e88-9238-5d5257f9796a
                )

        )

)

Edit

Here is some code to reproduce:

<?php

$xml = '<?xml version="1.0" encoding="UTF-8" ?>
<items>
    <item>
        <reference resourceIdentifier="52chgb7f-1a00-4eaf-ac8a-5d4557f9796a" />
        <reference resourceIdentifier="52cbccc3-b754-4e88-9238-5d5257f9796a" />
    </item>
    <item>
        <reference resourceIdentifier="52chgb7f-1a00-4eaf-ac8a-5d4557f9796a" />
    </item>
    <item>
        <reference resourceIdentifier="52chgb7f-1a00-4eaf-ac8a-5d4557f9796a" />
        <reference resourceIdentifier="52chgb7f-1a00-4eaf-ac8a-5d4557f9796a" />
        <reference resourceIdentifier="52cbccc3-b754-4e88-9238-5d5257f9796a" />
    </item>
</items>';

$items = new \SimpleXMLElement($xml);
foreach ($items as $item) {

    echo '<h1>Item</h1>';
    echo '<pre>';
    print_r($item);
    print_r($item->reference); // Returns always 1 SimpleXMLElement Object?
    print_r($item->reference->children()); // Returns always 1 SimpleXMLElement Object?
    echo '</pre>';

}
1

There are 1 answers

0
IMSoP On BEST ANSWER

The simple answer is: don't rely on print_r. The thing with SimpleXML is that it uses a lot of, for want of a better word, "magic", and print_r (and var_dump, var_export, and pretty much any other generic debug or serialize function) doesn't show you how it will behave. Also, and this is really important, a SimpleXMLElement does not contain any arrays.

I wrote a dedicated debug function which, while not perfect, does a better job of recursing through SimpleXML objects than the native ones.

The reason for this specific behaviour is that you can use $node->reference to refer to either the list of all children called reference, or the first such child. The following are all equivalent:

// Access as iterable list
foreach ( $node->reference as $ref ) {
    echo $ref['resourceIdentifier'];
    // only loop once
    break;
}

// Access as numerically indexed array
echo $node->reference[0]['resourceIdentifier'];

// Access first item by default
echo $node->reference['resourceIdentifier'];

This is extremely handy when you have a document that is "deep but narrow", e.g.

$xml = simplexml_load_string('<foo><bar><baz><quux hello="world" /></baz></bar></foo>');
echo $xml->bar->baz->quux['hello']; // world

Rather than you having to check whether a node is unique or multiple, SimpleXML just lets you write such an expression and ignore any multiples:

$xml = simplexml_load_string('<foo><bar><baz><quux hello="world" /><quux ignored="true" /></baz></bar><bar>ignored</bar></foo>');
echo $xml->bar->baz->quux['hello']; // world