Alex J
Alex J

Reputation: 537

In PHP, under what conditions does an unset() call reset the array index?

I've found a strange issue when using unset function in combination with a SimpleXML decoded array. The unset function applied on one of the index of such an array (which is numeric-indexed), seems to reset the array index.

This seems like an undocumented behavior to me (or more like a bug). Has anyone got an explanation why there's a "special reindexing" treatment for SimpleXML arrays?

Here's a test case that explains it.

<?php
$a = array( 1, 2, 3, 4 );
echo "Regular array, before unset(\$a[1]): " . print_r( $a, 1 );
unset( $a[1] );
echo "Regular array, after unset(\$a[1]): " . print_r( $a, 1 );

$xml = simplexml_load_string( <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<root>
<node>1</node>
<node>2</node>
<node>3</node>
<node>4</node>
<node>5</node>
</root>
EOT
 );

echo "SimpleXML array, before unset(\$a[1]): " . print_r( $xml, 1 );
unset( $xml->node[1] );
echo "SimpleXML array, after unset(\$a[1]): " . print_r( $xml, 1 );

The output that I get is,

Regular array, before unset($a[1]): Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
)
Regular array, after unset($a[1]): Array
(
    [0] => 1
    [2] => 3
    [3] => 4
)
SimpleXML array, before unset($a[1]): SimpleXMLElement Object
(
    [node] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
            [3] => 4
            [4] => 5
        )

)
SimpleXML array, after unset($a[1]): SimpleXMLElement Object
(
    [node] => Array
        (
            [0] => 1
            [1] => 3
            [2] => 4
            [3] => 5
        )

)

Upvotes: 2

Views: 324

Answers (3)

reko_t
reko_t

Reputation: 56430

The reason is that accessing $xml->node does not give you an actual array. $xml->node[1] returns you an instance of SimpleXMLElement, which has a magic method __unset that is called when you unset it. It doesn't use the PHP's default unset behavior as it does for the array.

Upvotes: 2

Mark Baker
Mark Baker

Reputation: 212412

If the array is actually an object rather than a simple array, and the class has a magic __unset() method defined, then the scripters may have choose to deliberately reindex the elements so that the keys remain sequential... beneficial for those coders who like looping through 'arrays' using for($i = 0; $i < count($nodes); $i++) rather than foreach($nodes as $node).

I imagine that SimpleXML is written in C rather than PHP, but the same principle may have been applied to prevent "breakages" when being used by the for($i = 0; $i < count($nodes); $i++) coders.

Upvotes: 2

JochenJung
JochenJung

Reputation: 7213

In your code you do

unset( $xml->node[1] );

not

unset($a[1])

like you describe in your output.

The unset( $xml->node[1] ); you do, would be:

unset($a[node][1])

And therefore it is correct.

Upvotes: 0

Related Questions