[NOTE: I solved this problem in the course of drafting the question, but figured I would proceed with posting it for future reference, since my extensive searching on the warnings delivered did not provide the solution and I figure this might help someone in the future.]
I have a class Thing
that has properties $subthing_1
, $subthing_2
, $subthing_3
, all of which are objects:
class Thing {
...
public $subthing_1; // object of type Subthing
public $subthing_2; // object of type Subthing
public $subthing_3; // object of type Subthing
...
}
If I want to get a particular subthing in an instance of Thing, I can do:
$thing->subthing_1
and this works just fine to deliver that subthing. But I want to generalize which of the subthings are called, so I have a routine that gets the name of a particular subthing, either 'subthing_1', 'subthing_2', or 'subthing_3', and stores it in a string in an array element. Thus, $subthings[4]
has string value 'subthing_1', for example, and
$thing->$subthings[4]
should deliver exactly the same as $thing->subthing_1
.
If I do
var_dump($subthings[4]);
the result is
string(10) "subthing_1"
and for
var_dump($thing);
the result is
object(Thing)#4 (87) {
...
["subthing_1"]=>
object(Category)#59 (12) {
...
}
...
}
Which is all fine and good. However, when I try to do this:
var_dump($thing->$subthings[4]);
I get this:
Warning: Array to string conversion ...
Warning: Undefined property: Thing::$Array ...
Warning: Trying to access array offset on value of type null ...
This confused me for a long time, because I couldn't see where an array was being converted to a string. $subthings[4]
is clearly a string, as indicated by var_dump($subthings[4])
, not an array.
These warnings are appearing in PHP 8.1 for code that worked just fine in PHP 5.5.
Eventually I reasoned that there must have been a syntax interpretation change somewhere between these two PHP versions.
Whereas in PHP 5.5, $thing->$subthings[4]
is interpreted as $thing->{$subthings[4]}
, in PHP 8.1 $thing->$subthings[4]
is interpreted as {$thing->$subthings}[4]
.
I have searched high and low for documentation of this change, but I guess I am not hitting on the right keywords. I hope someone here can supply an answer for where this change is documented.
The SOLUTION is to surround the arrays with curly braces to enforce the expected (and formerly default) parse ordering:
$thing->{$subthings[4]}
As pointed out by Don't Panic, this evaluation syntax change is documented here: https://www.php.net/manual/en/migration70.incompatible.php#migration70.incompatible.variable-handling.indirect