I needed a way to update an attribute, but I could not find any documented way to do this.
TL;DR: It's not only possible, but unbelievably simple. See the other note I submitted for what actually works (sorry, I could not fit it all in a single note due to the 4095 character limit).
After much experimentation, here's my findings of what does NOT work; hopefully, it saves you the time and frustration it cost me.
Given the following example:
<?php
$xml = <<<EOF
<?xml version="1.0" encoding="utf-8" ?>
<Animals>
<Dog/>
</Animals>
EOF;
$animals = new SimpleXMLElement($xml);
echo $animals->Dog->asXML();
?>
Test #1 - attempt to call addAttribute() twice
TL;DR: PHP Warning: SimpleXMLElement::addAttribute(): Attribute already exists
<?php
...
$animals->Dog->addAttribute('breed', "chihuahua");
echo $animals->Dog->asXML();
$animals->Dog->addAttribute('breed', "poodle");
echo $animals->Dog->asXML();
?>
Test #2 - attempt to iterate attributes() (an Iterator) by reference
TL;DR: An iterator cannot be used with foreach by reference
<?php
...
$animals->Dog->addAttribute('breed', "chihuahua");
echo $animals->Dog->asXML();
try {
foreach ($animals->Dog->attributes() as $attr => &$value) {
if ("breed" === $attr) {
$value = "poodle";
}
}
} catch (Throwable $e) {
echo $e->getMessage();
}
echo $animals->Dog->asXML();
?>
Test #3 - attempt to re-parse child element and then call addAttribute() on the newly parsed element, as suggested in a note I found here
TL;DR: PHP Warning: SimpleXMLElement::addAttribute(): Attribute already exists
<?php
...
$animals->Dog->addAttribute('breed', "chihuahua");
echo $animals->Dog->asXML();
$animals->Dog = new SimpleXMLElement($animals->asXML());
$animals->Dog->addAttribute('breed', "poodle");
echo $animals->Dog->asXML();
?>
Test #4 - attempt to modify @attributes array element
TL;DR: PHP Notice: Indirect modification of overloaded element of SimpleXMLElement has no effect
<?php
...
$animals->Dog->addAttribute('breed', "chihuahua");
echo $animals->Dog->asXML();
$dogAttrs = $animals->Dog->attributes();
$dogAttrs['@attributes']['breed'] = "poodle";
echo $animals->Dog->asXML();
?>
Test #5 - cast attributes() to array and set value of 'breed' element
TL;DR: does not update value in original object
<?php
...
$animals->Dog->addAttribute('breed', "chihuahua");
echo $animals->Dog->asXML();
$dogAttrs = (array) $animals->Dog->attributes();
$dogAttrs['@attributes']['breed'] = "poodle";
echo $animals->Dog->asXML();
?>