среда, 4 августа 2021 г.

Интерпретация переменных в строке

Сегодня еще один пост о всяких веселых способах написать код в php.

Всем известно (а если не известно, то читайте мануал), что в строках в двойных кавычках переменные и некоторые другие выражения обрабатываются и вместо этой переменной\выражения выводится результат. Простейший пример:

$number = 42;
echo "Number is $number";
// outputs "Number is 42"

Теперь зададимся вопросом - а можно ли как-то интерпретировать в строках какие-либо выражения? Например, сложение двух чисел. Естественно, написание в лоб приводит к ошибкам:

$a = 42;
$b = 24;
echo "Sum is {$a + $b}";

Что же делать? Понятно, что можно завести класс, объявить в нем метод суммирования, но это как-то много кода:

class Summator {
    public function sum($a, $b) {
        return $a + $b;
    }
}

$a = 42;
$b = 24;
$o = new Summator();
echo "Sum is {$o->sum($a, $b)}";
// outputs "Sum is 66"

Подумав еще немного можно прийти к следующему - создадим переменную, которая будет хранить анонимную функцию, и в строке вызовем эту переменную:

$a = 42;
$b = 24;
$sum = function($a, $b) { return $a + $b; };
echo "Sum is {$sum($a, $b)}";
// outputs "Sum is 66"

А с учетом стрелочных функций (с версии 7.4), которые имеют доступ к переменным родительской области видимости, код упрощается до такого:

$a = 42;
$b = 24;
$sum = fn() => $a + $b;
echo "Sum is {$sum()}";
// outputs "Sum is 66"

Ну и наконец самая безумная версия:

$a = 42;
$b = 24;
echo "Sum is ${0 * ${0}=$a+$b}";
// outputs "Sum is 66"

Что же здесь происходит?

Здесь мы пытаемся вывести переменную с названием, которое получается как результат умножения 0 на переменную ${0}. А значение ${0} является суммой значений $a и $b. Почему php выполняет присваивание значения переменной при парсинге строки - не знаю. Но тем не менее, мы получаем, что переменной ${0} присваивается 66. А так как результатом присваивания является присвоенное значение, то 0 * ${0}=$a+$b превращается в 0 * 66, и выражение ${0 * ${0}=$a+$b} сворачивается в ${0}. То есть мы хотим вывести переменную с названием 0, которую мы уже определили ранее, как сумму $a и $b. Вот и получаем в выводе 66.

Спасибо за внимание и никогда не пишите такой код)