How does PHP interpret &$this
? Why is it allowed?
I came to this question with the following issues, which looks like a bug in PHP 7.1 and 7.2.
It occurs with &$this
references and cross-namespace calls and call_user_func_array
.
I think &$this
is pretty weird and should not be allowed, but WordPress uses it for example.
Consider this code:
<?php
namespace N {
function callNeedRef( $a ) {
var_dump( $a );
call_user_func_array( 'needRef', $a );
}
}
namespace {
function needRef( &$r ) { }
function callNeedRef( $a ) {
var_dump( $a );
call_user_func_array( 'needRef', $a );
}
class C {
function f() {
$a = $this;
callNeedRef( array( &$a ) ); // no warning (expected), OK!
N\callNeedRef( array( &$a ) ); // no warning (expected), OK!
callNeedRef( array( &$this ) ); // no warning (expected), but 7.1,7.2: var_dump prints no '&'
N\callNeedRef( array( &$this ) ); // 7.1,7.2: warn and var_dump prints no '&'
}
}
echo "<pre>";
echo phpversion() . PHP_EOL;
$o = new C();
$o->f();
}
And its output:
7.2.0RC2
array(1) {
[0]=>
&object(C)#1 (0) {
}
}
array(1) {
[0]=>
&object(C)#1 (0) {
}
}
array(1) {
[0]=>
object(C)#1 (0) {
}
}
array(1) {
[0]=>
object(C)#1 (0) {
}
}
Warning: Parameter 1 to needRef() expected to be a reference, value given in reftest.php on line 6
As already stated in the code, the two last var_dump
s dont mark the object as reference. And the last call even produces as warning.
The val ($this
) is not global, the scope changes, therefore it get's ZCAL_STR_COPY
ied.
case EXTR_OVERWRITE:
/* GLOBALS protection */
if (var_exists && ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) {
break;
}
if (var_exists && ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this")) {
zend_class_entry *scope = zend_get_executed_scope();
if (scope && ZSTR_LEN(scope->name) != 0) {
break;
}
}
ZVAL_STR_COPY(&final_name, var_name);
break;
Thank's for making me look into PHP Source Code for array.c :)
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