As for SimpleXML itself, it is an internal class. The only interface it implements for PHP userspace is Traversable.
Internally when accessed with square brackets, SimpleXML looks for things depending on the value and type of the index/key.
If the type is integer (long), tries to find the zero-indexed, numbered element and offer its value. If you have a concrete node element like $root for the root element, $root[0] will represent the value of that element:
$root = new SimpleXMLElement('<root a="vala"></root>');
$root[0] = 'hello';
# <root a="vala">hello</root>
# ^^^^^- changed value
The root element is a bit uninteresting because there only exists one. It is more interesting with elements that have parents.
$root = new SimpleXMLElement('<root a="vala"><child /></root>');
$root->child[0] = 'hello';
# <root a="vala"><child>hello</child></root>
# ^^^^^- changed value
Sets the node-value of the first child element. An index up-one will add a new child:
$root = new SimpleXMLElement('<root a="vala"><child /></root>');
$root->child[1] = 'hello';
# <root a="vala"><child/><child>hello</child></root>
# ^-- added child --^
This pretty much works like with arrays. Strings that are an integer number, work like an integer:
$root->child['1'] = 'hello';
# <root a="vala"><child/><child>hello</child></root>
# ^-- added child --^
And leaving the brackets empty, will add a new element at the end:
$root->child[] = 'hello';
$root->child[] = 'world';
# <root a="vala"><child/><child>hello</child><child>world</child></root>
So far for integers and "no" offset. Like with a standard PHP array, this must not be confused with passing NULL. It would be converted to an empty string "".
With any string, SimpleXML will look for an attribute node instead of a child element node:
$root = new SimpleXMLElement('<root a="vala"></root>');
echo $root['a'], "\n"; # vala
This also works for adding attributes:
$root = new SimpleXMLElement('<root a="vala"></root>');
$root['b'] = 'hello'; # <root a="vala" b="hello"/>
An edge-case is using an empty string ("") or NULL because simplexml then errors out saying that an attribute with no name is invalid. Makes sense as attributes must have a name:
Warning: main(): Cannot write or create unnamed attribute in ...
Another more special case is the support of the __toString magic method. If you pass an object as offset, SimpleXML will try to convert it to string via the magic method. It will then use the returned string as described above.
To summarize: The SimpleXMLElement class does not implement the ArrayAccess interface but as it is an internal class, it can add an array-similar behavior. And SimpleXML does exactly that.
The utility function in PHP sources is called sxe_prop_dim_read.
But what about when you want to do something similar with your classes?
That is what the ArrayAccess interface is for. Implement it in your own classes. PHP already takes some of the work for you internally to make offsets more array-like: integer stay integer; string like an integer are converted to integer and booleans are converted to integer.
However ArrayAccess allows more than a standard array: valid offsets are floats, NULL, arrays and objects.
Especially with NULL, you are not able to differ between setting the offset NULL or setting a new element - both cases will provide NULL as offset.
An example implementation of the interface is available with another question: PHP, SPL, ArrayAccess Interface.