2017-09-29 18 views
5

Jak interpretuje PHP &$this? Dlaczego jest dozwolone?

Przyszłam na to pytanie z następującymi problemami, które wyglądają jak błąd w PHP 7.1 i 7.2. Występuje z odwołaniami &$this referencji i krzyżowych wywołań nazw i call_user_func_array. Myślę, że &$this jest dość dziwne i nie powinno być dozwolone, ale WordPress używa go na przykład.

Rozważmy następujący kod:

<?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(); 
} 

a jego produkcja:

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 

Jak już wspomniano w kodzie, dwa ostatnie var_dump s dont oznaczyć przedmiot jako odniesienie. A ostatnie połączenie jest nawet ostrzeżeniem.

+0

tylko jako aktualizacja. Oto, co dzieje się we wszystkich wersjach php: https://3v4l.org/8Ftbh#output –

Odpowiedz

1

Wartość val ($this) nie jest globalna, zakres zmienia się, dlatego otrzymuje wartość ZCAL_STR_COPY.

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; 

Dziękuję za co mi zajrzeć do kodu źródłowego PHP dla array.c :)