As per PHP documentation about Variable variables:
$this is a special variable that cannot be referenced dynamically
However it seems that it's false, at least on the version of PHP, I've tested (5.5.12).
class ThisIsBugged
{
public function __construct()
{
${'this'}->doSomething(); // This works, while it shouldn't
}
}
Question #1: How can it work? According to the documentation it should not.
But there's more.
class ThisIsBugged
{
public function __construct()
{
// This does not work, but it could. See below.
${'th' . 'is'}->doSomething();
}
}
It stops the execution as expected:
PHP Notice: Undefined variable: this
PHP Fatal error: Call to a member function doSomething() on a non-object.
Note that the statement {'th' . 'is'}
has been evaluated: "Undefined variable: this".
However (this is the strangest thing), referencing explicitly the special variable $this
, fixes all the dynamic references used before or after that within the method.
class ThisIsBugged
{
public function __construct()
{
// Now it works while it shouldn't
${'th' . 'is'}->doSomething();
// This fixes both the previous and the subsequent calls
$unused = $this;
// Now it works while it shouldn't
${'th' . 'is'}->doSomething();
}
}
Question #2: How an explicit reference to $this
can fix all the other dynamic references to $this
present in the whole method?
PHP uses a concept we call the compiled variables (CV) optimization. This means that instead of using a hashtable which maps variable names to their values, we use a plain array and index into it. The compiler knows which variable name corresponds to which index. Performing array index lookups is significantly faster than doing hashtable lookups.
The $this
variable will also be stored this way and its index is specially remembered as op_array->this_var
. If no $this
use is found this value is left uninitialized at -1
. When pushing a new execution context onto the VM stack PHP will check op_array->this_var
and, if it isn't -1
, initialize the $this
variable entry.
When a variable variable is accessed, PHP will walk through the CV table and construct a proper symbol hashtable from it. Of course it will only add variables which actually are in the CV table, so if it doesn't contain $this
you'll end up with an undefined variable lookup.
Now consider your three cases:
$this
and ${"this"}
are the same as far as the PHP compiler is concerned (after all the variable name is known at compile time in both cases).${"th"."is"}
is a $this
access as well. So this_var
stays uninitialized.$this
usage, as such this_var
will be set and also accessible through a variable-variable lookup.Note that the situation is different in PHP 7 - we'll always set this_var
on a variable variable lookup, so indirect $this
lookups should always work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With