Search code examples
phparraysobjectbraces

Warnings: Array to string conversion, undefined property in PHP 8.1 trying to call a property of an object (worked in PHP 5.5)


[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.


Solution

  • 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