Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 [ 112 ] 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

( Замечание

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

Генерация кода

во время выполнения

Так как PHP в действительности является транслирующим интерпретатором, в нем заложены возможности по созданию и выполнению кода программы прямо во время ее выполнения. То есть мы можем писать сценарии, которые в буквальном смысле создают сами себя, точнее, свой код! Это незаменимо при написании шаблонизаторов и функций, занимающихся динамическим формированием писем. Мы поговорим о таких функциях в части V книги.

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

int eval(string $code)

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

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

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

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

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

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

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

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

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



□ Тем не менее, синтаксические ошибки и предупреждения, возникающие при трансляции кода в $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 чисел:

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

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

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

Попробуйте-ка сделать это, не прибегая к услугам 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() .

Вторая строка, собственно, запускает тот код, который мы только что считали. Но gf+ie iif rfdlaafdlnn nceaiefec ?> с gffi+caflnn <? - nyafec indunc с gfdunc §iaf PHP? Наверное, вы уже догадались: суть в том, что функция eval() воспринимает свой параметр именно как код, а не как документ со вставками PHP-кода. В то же время, считанный нами файл представляет собой обгчный PHP-сценарий, т. е. документ со "вставками" PHP. Иными словами, настоящая инструкция include воспринимает файл в контексте документа, а функция eval() - в контексте кода. Поэтому-то мы и используем ?> - переводим текущий контекст в режим восприятия документа, чтобы eval() "осознала" статический текст верно. Мы еще неоднократно столкнемся с этим приемом в будущем.

Генерация функций

В последнем примере мы рассмотрели, как можно создать 100 функций с разными именами, написав программу длиной в 2 строчки. Это, конечно, впечатляет, но мы должны жестко задавать имена функций. Почему бы не поручить эту работу PHP, если нас не особо интересуют получающиеся имена?

1 Листинг 24.2. Генерация "анонимных" функций

$Funcs=array();

for($i=0; $i<=100; {

$id=uniqid("F");

eval("function $id() { return }");

$Funcs[]=$id;



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 [ 112 ] 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189