eval()
Функция eval() в PHP выполняет строку как PHP-код во время выполнения. Узнайте синтаксис, возвращаемые значения, риски безопасности и альтернативы.
Введение в функцию eval()
Функция eval() выполняет строку как PHP-код во время выполнения — в момент, когда скрипт достигает вызова eval(). Вместо того чтобы писать код, который PHP-парсер компилирует заранее, вы передаёте eval() строку, которая компилируется и выполняется на лету.
Это делает eval() одной из самых мощных — и самых опасных — конструкций языка. На этой странице рассматриваются синтаксис, возвращаемые значения, редкие случаи, когда функция действительно полезна, риски безопасности, делающие её крайней мерой, и более безопасные альтернативы, к которым стоит обратиться в первую очередь.
eval()— это языковая конструкция, а не обычная функция. Её нельзя вызвать косвенно через имя переменной-функции или передать в функции обратного вызова.
Синтаксис
eval(string $code): mixedЕдинственный аргумент — строка с PHP-кодом. Важно помнить несколько правил:
- Не включайте открывающий тег
<?php. Строка уже воспринимается как PHP-код, поэтому добавление<?phpвернёт интерпретатор в «режим HTML». - Код должен быть синтаксически корректным и завершённым. Отсутствующая точка с запятой или несбалансированная скобка приведут к ошибке разбора. Начиная с PHP 7, ошибка разбора внутри
eval()генерирует исключениеParseError, которое можно перехватить — в старых версиях возвращалосьfalse.
Возвращаемое значение
Значение, возвращаемое eval(), зависит от того, что делает выполняемый код:
- Если код содержит оператор
return,eval()возвращает это значение. - В противном случае возвращается
null.
<?php
$result = eval('return 2 + 3;');
echo $result; // 5Именно поэтому return внутри eval() завершает выполняемую строку, а не весь скрипт — управление возвращается на строку после eval(). О поведении return в обычных функциях читайте в разделе оператор return.
Базовый пример
Вот простейший пример использования — формирование строки кода и её выполнение:
Переменная $code содержит корректный PHP-код, выводящий Hello, world!. eval() компилирует и выполняет эту строку во время выполнения скрипта, отображая сообщение. Обратите внимание, что внутри строки нет тега <?php.
Безопасный перехват ошибок
Поскольку некорректный код генерирует ParseError, оберните недоверенный или сгенерированный код в блок try/catch, чтобы ошибочная строка не привела к краху всего запроса:
<?php
try {
eval('echo "missing semicolon"'); // no terminating ;
} catch (ParseError $e) {
echo "Could not evaluate: " . $e->getMessage();
}Вместо фатальной ошибки будет выведено сообщение «Could not evaluate», и скрипт продолжит работу.
Когда стоит использовать eval()?
В современном PHP — почти никогда, и это честный ответ. Среди редких оправданных случаев:
- Шаблонные/выражающие движки, которые компилируют пользовательский мини-язык в PHP-код (Twig и Blade делают нечто концептуально похожее, но с серьёзной изоляцией).
- Кэширование скомпилированной конфигурации в виде PHP-кода для последующего выполнения через
eval, хотя запись в реальный.php-файл и использованиеinclude— быстрее и безопаснее. - Образовательные или отладочные инструменты, например REPL, где входные данные полностью доверенные.
Если вычисляемое значение является данными (числами, JSON, списком параметров), eval() почти наверняка не нужен.
Риски безопасности
eval() выполняет всё, что ему передано. Если любая часть строки может быть подконтрольна пользователю, злоумышленник получит возможность выполнить произвольный код — читать файлы, удалять данные или захватить сервер. Это классическая уязвимость удалённого выполнения кода (RCE).
<?php
// NEVER do this:
$expr = $_GET['expr']; // attacker-controlled
eval("\$answer = $expr;"); // attacker can inject any PHPЗапрос вида ?expr=1; system('rm -rf /') выполнит внедрённую команду. Любой вызов eval() с пользовательскими данными — это гарантированная уязвимость.
Более безопасные альтернативы
Прежде чем прибегать к eval(), убедитесь, что ни одна из следующих альтернатив не подходит:
| Задача | Используйте вместо eval() |
|---|---|
| Разбор структурированных данных | json_decode() |
| Вызов функции, выбранной во время выполнения | Callback / переменные функции |
| Выполнение кода из файла | include / require |
| Сопоставление строки с поведением | match/switch или массив замыканий |
| Вычисление математических выражений | Специализированная библиотека-парсер выражений |
Заключение
eval() выполняет строку как PHP-код во время выполнения, возвращая результат оператора return внутри неё или null в противном случае. Это действительно мощный инструмент, но при этом один из главных источников уязвимостей — любые пользовательские данные, переданные в него, превращаются в ошибку удалённого выполнения кода. Используйте его только при полном доверии к входным данным и отсутствии подходящих встроенных конструкций, оборачивайте вызов в try/catch для перехвата ParseError и при любой возможности отдавайте предпочтение более безопасным альтернативам, описанным выше.