Динамически ссылка на $это не должно работать, но это делает


согласно документации PHP о переменные:

$это специальная переменная, на которую нельзя ссылаться динамически

однако кажется, что это ложь, по крайней мере, на версии PHP, которую я тестировал (5.5.12).

class ThisIsBugged
{
    public function __construct()
    {
        ${'this'}->doSomething(); // This works, while it shouldn't
    }
}

Вопрос № 1: как это может работать? Согласно документации этого делать не следует.

но это еще не все.

class ThisIsBugged
{
    public function __construct()
    {
        // This does not work, but it could. See below.
        ${'th' . 'is'}->doSomething();
    }
}

это останавливает исполнение как ожидалось:

PHP Примечание: неопределенная переменная: this

PHP фатальная ошибка: вызов функции-члена doSomething () на a не-объект.

обратите внимание, что заявление {'th' . 'is'} была оценена: "неопределенная переменная: этот".

однако (это самое странное), явно ссылаясь на специальной переменной $this, исправляет все динамические ссылки, используемые до или после этого в метод.

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

Вопрос № 2: как явная ссылка на $this можно исправить все другие динамические ссылки на $this присутствует во всем методе?

1 54
php

1 ответ:

PHP использует концепцию, которую мы называем оптимизацией скомпилированных переменных (CV). Это означает, что вместо использования хэш-таблицы, которая сопоставляет имена переменных с их значениями, мы используем простой массив и индекс в него. Компилятор знает, какое имя переменной соответствует какому индексу. Поиск индекса массива выполняется значительно быстрее, чем поиск хэш-таблиц.

The $this переменная также будет храниться таким образом, и ее индекс специально запоминается как op_array->this_var. Если нет $this использование найдено это значение остается неинициализированным в -1. При нажатии нового контекста выполнения на стек виртуальной машины PHP будет проверять op_array->this_var и, если это не так -1 инициализации $this переменной записи.

когда переменная переменная доступна, PHP пройдет через таблицу CV и построит из нее правильную хэш-таблицу символов. Конечно, он будет добавлять только переменные, которые на самом деле находятся в таблице CV, так что если он не содержит $this вы будете в конечном итоге с неопределенной переменной уважать.

теперь рассмотрим ваши три случая:

  1. $this и ${"this"} то же самое, что касается компилятора PHP (ведь имя переменной известно во время компиляции в обоих случаях).
  2. как PHP 5.компилятор x еще не выполняет свертку константных выражений, однако он не сможет обнаружить, что ${"th"."is"} это $this открыть, а также. Так что this_var остается неинициализированным.
  3. в последнем случае у вас есть простой $this использование, как таковых this_var будет установлен, а также доступны через переменную-переменная поиска.

обратите внимание, что в PHP 7 ситуация другая-мы всегда будем устанавливать this_var на переменную переменную поиска, так косвенно $this поиск должен работать всегда.