САМОУЧИТЕЛЬ PHP 4

Выполнение кода


int eval(string $code)

Эта функция делает довольно интересную вещь: она берет параметр $st и, рассматривая его как код программы на PHP, запускает. Если этот код возвратил какое-то значение оператором return (как, например, это обычно делают функции), eval()

также вернет эту величину.

Параметр $st представляет собой обычную строку, содержащую участок PHP-программы. То есть в ней может быть все, что допустимо в сценариях:

r

ввод-вывод, в том числе закрытие и открытие тэгов <? и ?>;

r    управляющие инструкции: циклы, условные операторы и т. д.;

r    объявления и вызовы функций;

r    вложенные вызовы функции eval().

Тем не менее, нужно помнить несколько важных правил[E127] [DK128] .

r    Код в $st

будет использовать те же самые глобальные переменные, что и вызвавшая программа. Таким образом, переменные не локализуются

внутри eval().



r    Любая критическая ошибка (например, вызов неопределенной функции) в коде строки $st

приведет к завершению работы всего сценария (разумеется, сообщение об ошибке также напечатается в браузер). Это значит, что мы не можем перехватить все ошибки в коде, вставив его в eval().

Последний факт вызывает довольно удручающие мысли. К сожалению, разработчики PHP опять не задумались о том, как было бы удобно, если бы eval() при ошибке в вызванном ей коде просто возвращала значение false, помещая сообщение об ошибке в какую-нибудь переменную (как это сделано, например, в Perl).

r    Тем не менее, синтаксические ошибки и предупреждения, возникающие при трансляции кода в $st, не приводят к завершению работы сценария, а всего лишь вызывают возврат из eval()значения ложь. Что ж, хоть кое-что.

Не забывайте, что переменные в строках, заключенных в двойные кавычки, в PHP интерполируются (то есть заменяются на соответствующие значения). Это значит, что, если мы хотим реже использовать обратные слэши для защиты символов-кавычек, нужно стараться применять строки в апострофах для параметра, передаваемого eval(). Например:


eval("$a=$b;");  // Íåâåðíî!

// Âû, âèäèìî, õîòåëè íàïèñàòü ñëåäóþùåå:

eval("\$a=\$b");

// íî êîðî÷å áóäåò òàê:

eval('$a=$b');

Возможно, вы спросите: зачем нам использовать eval(), если она занимается лишь выполнением кода, который мы и так можем написать прямо в нужном месте программы? Например, следующий фрагмент

eval('for($i=0; $i<10; $i++) echo $i; ');

эквивалентен такому коду:

for($i=0; $i<10; $i++) echo $i;

Почему бы всегда не пользоваться последним фрагментом? Да, конечно, в нашем примере лучше было бы так и поступить. Однако сила eval() заключается прежде всего в том, что параметр $st

может являться (и чаще всего является) не статической строковой константой, а сгенерированной переменной. Вот, например, как мы можем создать 100 функций с именами Func1()...Func100(), которые будут печатать квадраты первых 100 чисел:

Листинг 24.1. Генерация семейства функций

for($i=1; $i<=100; $i++)

  eval("function Func$i() { return $i*$i; }");

Попробуйте-ка сделать это, не прибегая к услугам eval()!

Я уже говорил, что в случае ошибки (например, синтаксической) в коде, обрабатываемом eval(), сценарий завершает свою работу и выводит сообщение об ошибке в браузер. Как обычно, сообщение сопровождается указанием того, в какой строке произошла ошибка, однако вместе с именем файла выдается уведомление, что программа оборвалась в функции eval(). Вот как, например, может выглядеть такое сообщение:

Parse error: parse error in eval.php(4) : eval()'d code on line 1

Как видим, в круглых скобках после имени файла PHP печатает номер строки, в которой была вызвана сама функция eval(), а после "on line" — номер строки в параметре eval() $st. Впрочем, мы никак не можем перехватить эту ошибку, поэтому последнее нам не особенно-то интересно.



Давайте теперь в качестве тренировки напишем код, являющийся аналогом инструкции include. Пусть нам нужно включить файл, имя которого хранится в $fname. Вот как это будет выглядеть:

$code=join("",File($fname));

eval("?>$code<?");

Всего две строчки, но какие...… Рассмотрим их подробнее.

Что делает первая строка — совершенно ясно: она сначала считывает все содержимое файла $fname по строкам в список, а затем образует одну большую строку путем "склеивания"

всех элементов этого списка. Заметьте, как получилось лаконично: нам не нужно ни открывать файл, ни использовать функцию fread()

или fgets().

Вторая строка, собственно, запускает тот код, который мы только что считали. Но çr÷le îír ddläârd?lnn? nceâîërec ?> c çrerí÷cârlnn? <? — nýarec înedunc? c çredunc? eîär PHP? Наверное, вы уже догадались: суть в том, что функция eval() воспринимает свой параметр именно как код, а не как документ со вставками PHP-кода. В то же время, считанный нами файл представляет собой обычный PHP-сценарий, т. е. документ со "вставками" PHP. Иными словами, настоящая инструкция include воспринимает файл в контексте документа, а функция eval() — в контексте кода. Поэтому-то мы и используем ?> — переводим текущий контекст в режим восприятия документа, чтобы eval() "осознала"

статический текст верно. Мы еще неоднократно столкнемся с этим приемом в будущем.


Содержание раздела