2017-09-29 1 views
5

Wie interpretiert PHP &$this? Warum ist es erlaubt?

Ich kam zu dieser Frage mit den folgenden Problemen, die wie ein Bug in PHP 7.1 und 7.2 aussieht. Es tritt mit &$this Referenzen und Cross-Namespace-Aufrufe und call_user_func_array auf. Ich denke, &$this ist ziemlich seltsam und sollte nicht erlaubt sein, aber WordPress verwendet es zum Beispiel.

Betrachten Sie diesen 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(); 
} 

und seine Ausgabe:

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 

Wie bereits im Code angegeben, sind die beiden letzten var_dump s nicht das Objekt als Referenz markieren. Und der letzte Anruf erzeugt sogar eine Warnung.

+0

nur als Update. Folgendes geschieht in allen PHP-Versionen: https://3v4l.org/8Ftbh#output –

Antwort

1

Das val ($this) ist nicht global, der Umfang ändert sich, daher wird es 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; 

Dankten für die Herstellung schauen mich in PHP-Quellcode für array.c :)