Документ из базы библиотеки компьютерной литературы 'Roga и Копыта' - www.roga.by.ru |
Содержание документа. | Скачать архив документа. | Другие документы по данной теме. | Вернуться в библиотеку. | Рассылка новых поступлений. | ЧАТЫ по интересам. |
III. Приложения
Приложение 0. Переход от PHP/FI 2.0 к PHP 3.0
PHP 3.0 полностью изменен. Его лексический анализатор стал намного более логичным и последовательным чем 2.0; версия 3.0 быстрее, и использует меньше ресурсов. Однако, некоторые усовершенствования повлекли частичную несовместимость в синтаксисе и функциональных возможностях.
Кроме того, в PHP 3.0 улучшен синтаксис и семантика, что также повлекло некоторую несовместимость. Однако, мы надеемся, что все эти усовершенствования к лучшему.
Эта глава поможет вам решить проблемы связанные с несовместимостью при переходе от PHP/FI 2.0 к PHP 3.0. Новые возможности здесь не рассматриваются.
Существует программа, которая может автоматически конвертировать старый PHP/FI 2.0 скрипт; вы можете найти ее в подкаталоге convertor дистрибутива PHP 3.0. Эта программа только отслеживает изменения синтаксиса, поэтому, в любом случае, вам придется прочитать эту главу внимательно.
Открывающий и закрывающий тэги
Первое, что вы вероятно заметите - это то что открывающий и закрывающий тэги PHP изменены. Старая <?> форма была заменена тремя новыми возможными формами:
Пример 0-1. Изменение: старые открывающий и закрывающий тэги:
<? echo "This is PHP/FI 2.0 code.\n"; > |
Начиная с версии 2.0, PHP/FI поддерживает также следующий формат:
Пример 0-2. Изменение: новые открывающий и закрывающий тэги, первый вариант:
<? echo "This is PHP 3.0 code!\n"; ?> |
Заметьте, что закрывающий тэг теперь состоит из знака вопроса и знака "больше" вместо только "больше". Однако, если Вы планируете использовать XML на вашем сервере, у вас будут проблемы с этим вариантом, так как PHP может попробовать исполнить разметку XML в документах XML как код PHP. Из-за этого, было внесено следующее изменение:
Пример 0-3. Изменение: новые тэги начала и конца, второй вариант:
<?php echo "This is PHP 3.0 code!\n"; ?> |
Из-за проблем с редакторами, не поддерживающими инструкции обработки (например Microsoft FrontPage), были введены следующие изменения:
Пример 0-4. Изменение: новые тэги начала и конца, третий вариант:
<script language="php"> echo "This is PHP 3.0 code!\n"; </script> |
Синтаксис операторов if..endif
"Альтернативный" способ описания блока if/elseif/else, с использованием, if(); elseif (); else; endif; не мог быть эффективно осуществлен без серьезного усложнения компиллятора/интерпретатора, из-за этого его синтаксис был изменен:
Пример 0-5. Изменение: старый синтаксис if..endif:
if ($foo); echo "yep\n"; elseif ($bar); echo "almost\n"; else; echo "nope\n"; endif; |
Пример 0-6. Изменение: новый синтаксис if..endif:if ($foo): echo "yep\n"; elseif ($bar): echo "almost\n"; else: echo "nope\n"; endif; |
Точки с запятой были заменены двоеточиями во всех операторах, за исключением завершающего блок (endif).
Точно так же как, с if..endif, был изменен синтаксис while..endwhile:
Пример 0-7. Изменения: старый, while..endwhile синтаксис:
while ($more_to_come); ... endwhile; |
Пример 0-8. Изменения: новый синтаксис while..endwhile:
while ($more_to_come): ... endwhile; |
Внимание! |
Используя устаревший синтаксис в PHP 3.0 вы получите бесконечный цикл. |
В PHP/FI 2.0 использовалась левая часть выражения для определения типа результата. PHP 3.0 учитывает обе части выражения для определения типа результата; это может привести к неожиданным результатам работы скриптов 2.0.
Рассмотрите этот пример:
$a[0]=5; $a[1]=7; $key = key($a); while ("" != $key) { echo "$keyn"; next($a); }
В PHP/FI 2.0 мы получили бы индексы $a. В PHP 3.0 мы не увидим ничего. Причина в том что в PHP 2.0, переменная в левой части выражения - строка; было выполнено сравнение, действительно "" не равно "0", и цикл был пройден. В PHP 3.0, при выполнении операции сравнения строковой и целочисленных переменных, строка будет преобразована в целое число и далее аргументы сравниваются как целые. Это означает в данном случае, что сравненивается значение функции atoi("") которое равно 0, и variablelist которое также равно 0; цикл не выполняется ни разу.
Исправить это достаточно просто. Замените начало на:
while ((string)$key != "") {
Сообщения об ошибках PHP 3.0, как правило, точнее чем в 2.0. Вместо указания фрагмента кода, вызвавший ошибку, вы получаете имя файла и номер строки.
Сокращенная операция вычисления логических выражений
В PHP 3.0 используется метод сокращенного вычисления логических выражений. Это означает что в выражении (1 || test_me()), функция test_me() не вызывается, так как результат функции уже не сможет изменить результат этого логического выражения.
Эта незначительная, на первый взгляд, проблема совместимости может приести к неожиданным последствиям.
Значения true/false, возвращаемые функциями
Большинство внутренних функции были переписаны; теперь они возвращают TRUE, в случае удачи и FALSE в противном случае, тогда как в PHP/FI 2.0 возвращаются 0 и -1 соответственно. Эти новые возможности позволяют создавать более логичный код, такой так $fp = fopen("/your/file") or fail("darn!");. Так как PHP/FI 2.0 не имел четких правил, относительно того, что должна вернуть функция в случае неудачи, в большинстве случаев скрипты использующие подобные функции должны быть проверены вручную после проверки конвертером.
Пример 0-9. Изменения 2.0: возвращаемые значения, старый код:
$fp = fopen($file, "r"); if ($fp == -1); echo("Could not open $file for reading<br>\n"); endif; |
Пример 0-10. Изменения 2.0: возвращаемые значения, новый код:
$fp = @fopen($file, "r") or print("Could not open $file for reading<br>\n"); |
То есть вы не можете читать массив в цикле, выполняющем $data = $array[]. Используйте current()и next().
Кроме того, выражение $array1[] = $array2 не добавляет значения массива $array2 к $array1, но добавляет $array2 как последний элемент $array1. См. также поддерку многомерных массивов.
Пример 0-11. Изменения 2.0: сложение для строковых переменных
echo "1" + "1"; В PHP 2.0 значение этого выражения - 11, а в PHP 3.0 - 2. Используйте вместо него: echo "1"."1"; $a = 1; $b = 1; echo $a + $b; Значение этого выражения = 2 для PHP 2.0 и 3.0. $a = 1; $b = 1; echo $a.$b; Это выражение вернет 11 в PHP 3.0. |
Приложение 0. Программирование на PHP
Добавление функций в PHP3
Все функции выглядят следующим образом:
void php3_foo(INTERNAL_FUNCTION_PARAMETERS) { }
Это общий вид функции, даже если она не имеет аргументов.
Аргументы всегда имеют тип pval. Этот тип представляет собой объединение (union), в котором содержится фактический тип аргумента. В том случае, если ваша функция принимает несколько аргументов, вы можете сделать что-нибудь вроде этого в начале вашей функции:
Пример 0-1. Объявление переменных:
pval *arg1, *arg2; if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&arg1,&arg2)==FAILURE) { WRONG_PARAM_COUNT; } |
Обратите внимание: аргументы могут быть по значению или по ссылке. В любом случае вы должны передать &(pval *) в getParameters. Если вы хотите проверить, был ли параметр передан ссылкой или нет, вы можете использовать функцию ParameterPassedByReference(ht,n), она вернет 1 или 0.
Если изменяете один из параметров, переданный по ссылке или по значению, вы можете вызвать pval_destructor, или, в том случае, если это массив, вы можете использолвать функцию, подобную одной из internal_functions.h, в котоых return_value является массивом.
Если вы собираетесь преобразовывать параметр к IS_STRING - сначала создайте новую строку с помощью estrdup() и укажите ее длину, только после этого преобразуйте к IS_STRING. Если вы изменяете строку параметра уже являющегося IS_STRING или IS_ARRAY, сначала придется использовать pval_destructor.
Функции с переменным числом аргументов
Функция может принимать неопределенное количество аргументов. Например, в случае, если ваша функция принимает два или три аргумента, можно использовать следующий код:
Пример 0-2. Функции, принимающие несколько аргументов
pval *arg1, *arg2, *arg3; int arg_count = ARG_COUNT(ht); if (arg_count < 2 || arg_count > 3 || getParameters(ht,arg_count,&arg1,&arg2,&arg3)==FAILURE) { WRONG_PARAM_COUNT; } |
Использование аргументов функции
Тип каждого аргумента означен в поле type структуры pval. Этот тип может быть любым из приведенных ниже:
Таблица 0-1. Типы переменных PHP
IS_STRING | String |
IS_DOUBLE | Double-precision floating point |
IS_LONG | Long integer |
IS_ARRAY | Array |
IS_EMPTY | None |
IS_USER_FUNCTION | ?? |
IS_INTERNAL_FUNCTION | ?? (если не может быть передана в функцию - удаляется) |
IS_CLASS | ?? |
IS_OBJECT | ?? |
Если вы получаете аргумент одного типа и хотели бы использовать его как аргумент другого типа, или если вы хотите жестко определить тип аргумента - используйте одну из преобразующих функций:
convert_to_long(arg1); convert_to_double(arg1); convert_to_string(arg1); convert_to_boolean_long(arg1); /* Если строка равна "" или "0" возвращает 0, во всех иных случаях 1 */ convert_string_to_number(arg1); /* Преобразует строку к LONG или DOUBLE в зависимости от содержания */
Эти функции только выполняют преобразование аргумента, они не возвращают значений.
Тип переменной обозначается в объединении:
Память, необходимая внутри функции, должна быть зарезервирована функциями emalloc() или estrdup(). Это функции управления памятью, которые выглядят и работают как обычные malloc() и strdup(). Память освобождается с помощью efree().
В программе могут быть использованы два вида памяти: область памяти, которая будет использована переменными, и временная память для функций. Когда вы присваиваете строковое значение переменной первого типа, вы должны предварительно выделить область памяти при помощи emalloc() or estrdup(). Вы НЕ должны освобождать эту память, если только вы не переписываете знаение переменной в той же функции (это считается не очень хорошим стилем программирования).
Для работы с временной/постоянной памятью необходимо использовать три функции: emalloc(), estrdup(), и efree(). Они работают ТАКЖЕ как их "двойники". Память, выделенную с помощью emalloc() или estrdup() вы должны освободить с помощью efree(), иначе область памяти будет утеряна. Под словами "также, как двойники" мы имеем в виду следующее: если вы пытаетесь освободить память, которая не была выделена с помощью emalloc() или estrdup() вы скорее всего получите ошибку сегментации (segmentation fault). Поэтому будьте внимательны и не забывайте освобождать память после использования.
Если вы выполняете компиляцию с опцией "-DDEBUG", PHP3 выдаст список всех блоков памяти, которые были выделены м помощью emalloc() или estrdup(), но не будут освобождены после завершения скрипта.
Установка переменных в таблице символов
Для упрощения доступа к переменным в таблице символов определены следующие макросы:
SET_VAR_STRING(имя,значение) [1]
SET_VAR_DOUBLE(имя,значение)
SET_VAR_LONG(имя,значение)
Таблицы символов в PHP 3.0 реализованы в виде хэш-таблиц (hash table). В любой момент времени, &symbol_table указывает на 'главную' таблицу символов, а active_symbol_table указывает на активную в данный момент (они идентичны при запуске, или различны - внутри функции).
Следующие примеры используют 'active_symbol_table'. Вам придется заменить это на &symbol_table ели вы хотите работать с 'главной' таблицей символов. Те же самые функции можно применять и к массивам,как показано ниже.
Пример 0-3. Проверка наличия $foo в таблице символов
if (hash_exists(active_symbol_table,"foo",sizeof("foo"))) { существует... } else { не существует } |
Пример 0-4. Вычисление размера переменной в таблице символов
hash_find(active_symbol_table,"foo",sizeof("foo"),&pvalue); check(pvalue.type); |
В PHP 3.0 маcсивы реализованы с использованием тех же хэш-таблиц, что и в таблицах символов. Это означает что приведенные функции можно использовать и для проверки переменных внутри массивов.
В том случае, если вы хотите определить новое множество в таблице символов:
Сначала, вы можете проверить наличие, используя hash_exists() или hash_find().
Потом инициализируйте множество:
Пример 0-5. инициализация нового множества
pval arr; if (array_init(&arr) == FAILURE) { failed... }; hash_update(active_symbol_table,"foo",sizeof("foo"),&arr,sizeof(pval),NULL); |
Объявление нового (пустого) массива $foo в активной таблице символов.
Вот так вы можете добавить новые элементы:
Пример 0-6. Добавление элементов к массиву
pval entry; entry.type = IS_LONG; entry.value.lval = 5; /* определяет $foo["bar"] = 5 */ hash_update(arr.value.ht,"bar",sizeof("bar"),&entry,sizeof(pval),NULL); /* определяет $foo[7] = 5 */ hash_index_update(arr.value.ht,7,&entry,sizeof(pval),NULL); /* определяет следующее свободное место в $foo[], * $foo[8], to be 5 (работает как и в php2) */ hash_next_index_insert(arr.value.ht,&entry,sizeof(pval),NULL); |
Если вы хотите изменить значение, в хэш-таблице, вы должны сначала считать его. Для того чтобы избежать этого на верхнем уровне, вы можете добавлять pval ** к функции выполняющей добавление (обновление произойдет с адресом pval * добавляемого элемента). Если это значение NULL (как в приведенных примерах) - параметр будет проигнорирован.
hash_next_index_insert() использует примерно такую же логику как и "$foo[] = bar;" в PHP 2.0.
Если вы создаете новый массив с целью возврата его из функции, можно инициализировать его так же как в примере выше:
if (array_init(return_value) == FAILURE) { failed...; }
...и добавлять новые значения вспомогательными функциями:
add_next_index_long(return_value,long_value); add_next_index_double(return_value,double_value); add_next_index_string(return_value,estrdup(string_value));
Конечно, если добавление не было выполнено правильно после инициализации множества, вероятно вам понадобится проверить множество сначала:
pval *arr; if (hash_find(active_symbol_table,"foo",sizeof("foo"),(void **)&arr)==FAILURE) { can't find... } else { use arr->value.ht... }
Обратите внимание: hash_find получает лишь ссылку на указатель на pval, а не сам указатель на pval.
Практически любая hash-функция возвращает SUCCESS или FAILURE (hash_exists() возвращает булево значение).
Возврат значений простых типов
Для упрощения возврата значений из функций определены следующие макросы:
Макросы RETURN_* устанавливают значение возвращаемое значение функции и возвращают управление:
Макросы RETVAL_* устанавливают возвращаемое значение, но не возвращает управление.
Все строковые макросы вызывают функцию estrdup() для переданного аргумента, поэтому вы можете спокойно освободить память, занятую под аргумент после выполнения макроса, или использовать статическую память.
Если ваша функция возвращает логическое значение, используйте RETURN_TRUE и RETURN_FALSE.
Возврат значений сложных типов
Ваша функция может также возвращать и сложные значения; такие как объект или массив.
Возвращение объекта:
Регистрация метода выполняется следующим образом:
add_method( return_value, function_name, function_ptr );
Функции для добавления полей(свойств):
Возвращение массива: