Подтвердить что ты не робот

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

В соответствии с документацией 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: переменная Undefined: this

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

Обратите внимание, что выражение {'th' . 'is'} было оценено: "Undefined variable: this".

Однако (это самая странная вещь), явно ссылаясь на специальную переменную $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, присутствующие во всем методе?

4b9b3361

Ответ 1

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

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

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

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

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

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