Новые книги

Instagram сегодня – самая популярная и удобная площадка, с помощью которой можно стать действительно знаменитым. Петр Плосков – Instagram-продюсер № 1 в России, занимающийся продвижением Дмитрия Маликова, Натальи Рудовой, Марии Миногаровой, Иды Галич, Ольги Медынич, Ники Вайпер и других знаменитостей с миллионными аудиториями. В своей книге Петр рассказывает обо всем, что необходимо знать, чтобы стать следующей звездой.
Эта книга полностью обновлена и тщательно пересмотрена. Она является необходимым пособием для руководителей информационных служб, технических консультантов и системных администраторов R/3, которые хотят иметь полное представление об администрировании Basis.

Знания, полученные "из первых рук" от различных специалистов SAP Global Support, работавших над реализацией более 20000 систем R/3, служат основой этой книги, которая научит выполнять все критически важные задачи системного администрирования с оптимальной эффективностью. Она учит быстро принимать правильные решения в сложных ситуациях, используя рекомендации экспертов и ценные рекомендации из реального мира, которые делают это уникальное пособие необходимым для повседневного использования.

Кроме всего прочего, эта книга является ценным источником, помогающим подготовиться к экзамену СТС (Certified Technical Consultant) no R/3 Release 4.6C и Enterprise.

В руководстве рассмотрены:

# Настройка системной инфраструктуры.

# Администрирование клиента.

# Пользователи и полномочия.

# Фоновая обработка.

# Архивирование данных.

# Администрирование спула.

# Обслуживание инстанций.

# Системный мониторинг.

И многое другое.

III. Приложения



III. Приложения


Переход от PHP/FI 2.0 к PHP 3.0
Разработка PHP
Отладчик PHP

Приложение 0. Переход от PHP/FI 2.0 к PHP 3.0


Несовместимость в 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).

Синтаксис while


Точно так же как, с 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");

Прочие изменения


  • Модуль Apache в PHP 3.0 не поддерживает Apache версий до 1.2. - необходима версия Apache 1.2, или более поздняя.
  • echo() больше не поддерживает строку формата. Используйте printf().
  • В PHP/FI 2.0, вызов $foo[0] имел тот же эффект как и $foo. Это устранено в PHP 3.0.
  • Чтение массивов в виде $array[] больше не поддерживается

    То есть вы не можете читать массив в цикле, выполняющем $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_STRINGString
IS_DOUBLEDouble-precision floating point
IS_LONGLong integer
IS_ARRAYArray
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 в зависимости от содержания */

Эти функции только выполняют преобразование аргумента, они не возвращают значений.

Тип переменной обозначается в объединении:

  • IS_STRING: arg1->value.str.val
  • IS_LONG: arg1->value.lval
  • IS_DOUBLE: arg1->value.dval

Управление памятью в функциях


Память, необходимая внутри функции, должна быть зарезервирована функциями 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(имя,значение)

[1]

Таблицы символов в 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_* устанавливают значение возвращаемое значение функции и возвращают управление:

  • RETURN
  • RETURN_FALSE
  • RETURN_TRUE
  • RETURN_LONG(l)
  • RETURN_STRING(s,dup) если dup - true, дублирует строку
  • RETURN_STRINGL(s,l,dup) возвращает строку (s) определенной длины (l).
  • RETURN_DOUBLE(d)

Макросы RETVAL_* устанавливают возвращаемое значение, но не возвращает управление.

  • RETVAL_FALSE
  • RETVAL_TRUE
  • RETVAL_LONG(l)
  • RETVAL_STRING(s,dup) если dup - true, дублирует строку
  • RETVAL_STRINGL(s,l,dup) возвращает строку (s) определенной длины (l).
  • RETVAL_DOUBLE(d)

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

Если ваша функция возвращает логическое значение, используйте RETURN_TRUE и RETURN_FALSE.

Возврат значений сложных типов


Ваша функция может также возвращать и сложные значения; такие как объект или массив.

Возвращение объекта:

  1. Вызвать object_init(return_value).
  2. Присвоить полям значения. Функции, доступные для этого, перечислены ниже.
  3. Возможно, зарегистрировать функции для данного объекта. Для того, чтобы иметь доступ к данным объекта, функция должна получить значение "this" из active_symbol_table. Его типом является IS_OBJECT. По сути, это обычная хэш-таблица, т.е. вы можете использовать хэш-функции с полем .value.ht.

Регистрация метода выполняется следующим образом:

add_method( return_value, function_name, function_ptr );

Функции для добавления полей(свойств):

  • add_property_long( return_value, property_name, l ) - Добавляет поле 'property_name', типа long
  • add_property_double( return_value, property_name, d ) - То же, тип double
  • add_property_string( return_value, property_name, str ) - То же, тип string
  • add_property_stringl( return_value, property_name, str, l) - То же, тип string длиной 'l'

Возвращение массива:

  1. Вызвать array_init(return_value).
  2. Присвоить значения. Функции доступные для этой цели перечислены ниже.

Функции для добавления элементов:

  • add_assoc_long(return_value,key,l) - добавить значение, ассоциированое с ключом 'key' типа long
  • add_assoc_double(return_value,key,d)
  • add_assoc_string(return_value,key,str)
  • add_assoc_stringl(return_value,key,str,length) - указывается длина строки
  • add_index_long(return_value,index,l) - добавить значение элемента 'index' типа long
  • add_index_double(return_value,index,d)
  • add_index_string(return_value,index,str)
  • add_index_stringl(return_value,index,str,length) - указывается длина строки
  • add_next_index_long(return_value,l) - добавляется элемент массива в свободное место, тип long
  • add_next_index_double(return_value,d)
  • add_next_index_string(return_value,str)
  • add_next_index_stringl(return_value,str,length) - указывается длина строки

Использование списка ресурсов


В PHP 3.0 имеется стандартные методы для работы с разными типами ресурсов. Это сделано для замены локально связанных списков в PHP 2.0.

Доступные функции:

  • php3_list_insert(ptr, type) - возвращает идентификатор 'id' только что добавленного ресурса
  • php3_list_delete(id) - удаляет ресурс с идентификатором id
  • php3_list_find(id,*type) - возвращает указатель на ресурс, заданный идентификатором id, обновляет тип

Обычно эти функции используются драйверами SQL, хотя и могут используваться в любом другом месте, например, при работе с файловыми дескрипторами.

Пример работы с этими функциями показан ниже.

Пример 0-7. Добавление нового ресурса
RESOURCE *resource;

/* ...выделение памяти под ресурс и создание его... */
/* добавление ресурса в список */
return_value->value.lval = php3_list_insert((void *) resource, LE_RESOURCE_TYPE);
return_value->type = IS_LONG;
Пример 0-8. Использование существующего ресурса
pval *resource_id;
RESOURCE *resource;
int type;

convert_to_long(resource_id);
resource = php3_list_find(resource_id->value.lval, &type);
if (type != LE_RESOURCE_TYPE) {
	php3_error(E_WARNING,"ресурс с номером %d: неправильный тип",resource_id->value.lval);
	RETURN_FALSE;
}
/* ...использование ресурса... */
Пример 0-9. Удаление ресурса
pval *resource_id;
RESOURCE *resource;
int type;

convert_to_long(resource_id);
php3_list_delete(resource_id->value.lval);

Типы ресурсов должны быть зарегистрированы в php3_list.h в списке list_entry_type. Кроме того, вы должны написать деструктор для каждого типа ресурсов в list_entry_destructor() файла list.c. Если вы не предпринимаете никаких дополнительных действий в деструкторе, вы должны добавить пустой деструктор.

Использование таблиц постоянных ресурсов


В PHP 3.0 существует методы хранения постоянных ресурсов (ресурсов, которые сохраняются между вызовами). Один из модулей, который использует эту возможность - модуль MySQL, а также mSQL; вы можете изучить правила использования постоянных ресурсов читая код mysql.c. Следует обратить внимание на функции:

php3_mysql_do_connect
php3_mysql_connect()
php3_mysql_pconnect()

Основная идея таблиц постоянных ресурсов заключается в следующем:

  1. Программируется модуль для работы с обычными списками ресурсов (см. секцию 9)
  2. Программируется дополнительные функции связи, которые проверяют, существует ли ресурс в таблице постоянных ресурсов. Если да, он регистрируется как в обычном списке ресурсов указателем на таблицу постояннвых ресурсов. После этого все должно заработать (см. 1.). Если ресурса не существует, тогда необходимо создать его, добавить в таблицу постоянных ресурсов и добавить указатель на нее в таблицу обчных ресурсов.

Если вы откроете файл mysql.c, вы заметите, что переписывать ничего не пришлось, за исключением более сложных функций связи.

Существует набор функций для работы с таблицами постоянных ресурсов, в котором функции для работы с таблицами постоянных ресурсов аналогичны функциям для работы с обычными списками ресурсов. В этом случае 'list' заменяется на 'plist':

  • php3_plist_insert(ptr, type) - возвращает дескриптор созданного ресурса
  • php3_plist_delete(id) - удаляет ресурс с дескриптором id
  • php3_plist_find(id,*type) - возвращает указатель на ресурс с дескриптором id, устанавливает 'type'

Однако, эти функции могут оказаться бесполезными когда вы создаете постоянный модуль. Можно пользоваться тем, что постоянные таблицы ресурсов реализованы как хэш-таблицы. Например, в модулях MySQL/mSQL, когда вызывается pconnect(), создается строка на основе имени хоста, имени пользователя и его пароля и эта строка помещается в хэш-таблицу как ключ. В следующий раз когда будет вызвана pconnect() с теми же параметрами хоста, пользователя и пароля, будет сгенерирован тот же самый ключ и SQL-связь будет найдено в списке постоянных ресурсов.

Чтобы более полно понять работу функций plist* с хэш-таблицами ознакомтесь с файлами mysql.c или msql.c.

Внимание: ресурсы, предназначеные для таблицы постоянных ресурсов НЕ ДОЛЖНЫ создаваться с помощью менеджера памяти, т.е. они не должны быть созданы с использованием emalloc(), estrdup() и т.д. Вместо этого вы должные использовать обычные malloc(), strdup() и т.д. Причина этого проста: после исполнения запроса каждый участок памяти, выделенный меджером, удаляется. Следовательно не можете использовать менеджер памяти, так как список постоянных ресурсов не должен быть удален в конце сеанса.

Когда вы регистрите ресурс, который собираетесь добавить в таблицу постоянных, вы должны добавить деструкторы для них и в таблицу постоянных ресурсов, и обычных. Дескриптор в таблице обычных ресурсов должен быть пустым. Напротив, деструктор постоянного ресурса должен правильно освободить память, SQL-связи и т.д. Помните, что вы обязаны предусмотреть деструктор для любого типа ресурсов, даже если он будет пустым. Помните так же о том, что из-за того, что функции типа emalloc() не используются с постоянными ресурсами, вы не должны пользоваться в деструкторе функциями типа efree().

Директивы времени выполнения (runtime)


Многие возможности PHP3 могут быть сконфигурированы во время выполнения. Конфигурационные директивы могут быть либо в файле php3.ini, либо, в случае использования Apache, в файлах .conf модуля Apache. Преимущесво использования файлов .conf модуля Apache заключается в том, что в этом случае можно предусмотреть настройки для каждого каталога в отдельности. Эта возможность особенна полезна когда сервер поддерживает несколько виртуальных хостов.

Ниже описаны действия, которые необходимо предпринять для добавления директивы:

  1. Добавьте директиву в секцию php3_ini_structure в mod_php3.h.
  2. В файле main.c, отредактируйте функцию php3_module_startup и добавьте подходящие вызовы cfg_get_string() или cfg_get_long().
  3. Добавьте директиву, ограничения и комментарий в структуру php3_commands в mod_php3.c. Заметьте, что только RSRC_CONF-директивы могут присутствовать в .conf файлах Apache. Директивы OR_OPTIONS могут присутствовать где угодно, включая файлы .htaccess.
  4. В php3take1handler() или в php3flaghandler() добавьте подходящую вашей директиве запись.
  5. В разделе конфигурации функции _php3_info() в info.c необходимо добавить директиву.
  6. После этого, естественно, вы должны использовать вашу директиву где-либо. Вызвать ее можно с помощью php3_ini.directive.

Вызов пользовательских функций


Для вызова пользовательских функций из внутренней нужно использовать call_user_function().

Функция call_user_function() возвращает SUCCESS в случае успеха, и FAILURE в том случае если функция не найдена. Вы должны проверить возвращенное значение! Если возврашен SUCCESS, вы отвечаете за удаление retval и pval. В случае возврата FAILURE, значение retval не определено.

Все внутренние функции должны быть сконструированы так, чтобы возможно было повторное использование ее. Это в частности означает, что в них не должны использоваться глобальные или статические переменные.

Функция call_user_function() принимает шесть аргументов:

HashTable *function_table


Хэш-таблица в которой производится поиск функции.

pval *object


Указатель на объект, с которым вызывается функция. NULL если вызывается глобальная функция. В первом случае аргумент function_table игнорируется и берется и определяется из объекта. Объект может быть изменен функцией (внутри функции он доступен через указатель $this). Если вы не хотите, чтобы это произошло, передайте копию объекта.

pval *function_name


Имя вызываемой функции. Должно быть pval IS_STRING со значениями function_name.str.val и function_name.str.len установленными соответственно. Значение function_name изменяется вызовом call_user_function() - конвертируется в нижний регистр (прописные буквы). Если вы этого не хотите, передайте копию имени функции.

pval *retval


Указатель на структуру pval, в которую записывается возвращаемое функцией значение. Структура должна быть создана заранее, call_user_function() сама по себе не создает ничего.

int param_count


Число параметров, передаваемое функции.

pval *params[]


Массив указателей на значения, которые передаются в вызываемую функцию; первый аргумент имеет смещение 0, второй 1 и т.д. Массив является массивом указателей на pval. Аргументы пересылаются по ссылке, из чего следует, что если функция меняет аргумент, меняется и первоначальное значение. Опять же, если вы хотите этого избежать, передайте ссылку на копию объекта.

Сообщения об ошибках


Чтобы выдать сообщение об ошибке внутри функций вы должны использовать функкцию php3_error(). Она принимает как минимум два параметра -- первый это категория ошибки, второй - форматирующая строка (как в стандартной функции printf()), за которым могут следовать аргументы форматирующей строки. Ниже представлены категории ошибок:

E_NOTICE


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

E_WARNING


Сообщения этого типа выводятся, но не прерывают выполнение скрипта. Они сообщают, что существует ошибка, которая должна быть отслежена скриптом до того, как будет сделан вызов. Примером служит вызов ereg() с неправильным регулярным выражением.

E_ERROR


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

E_PARSE


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

E_CORE_ERROR


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

E_CORE_WARNING


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

Взгляд вглубь PHP


Приложение 0. Отладчик PHP


Использование отладчика


Отладчик PHP полезен при отслеживании неочевидных ошибок. Он работает через TCP порт каждый раз, когда стартует PHP. Все сообщения об ошибках из запроса будут посланы по этому TCP соединению. Информация этого раздела нужна при работе с такими редакторами как Emacs, или в интегрированной среде разработки (IDE).

Действия по установке отладчика:

  1. Задайте порт TCP, который будет использоваться отладчиком в php3.ini (debugger.port) и разрешите его использование ( debugger.enabled).
  2. Установите пассивный сокет на этот порт (например, командой socket -l -s 1400 в UNIX).
  3. Внутри вашего кода запустите debugger_on(host), где host - запустите IP-адрес хоста, на котором запущен пассивный сокет.

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

Протокол отладчика


Протокол отладчика основан на отдельных строках. Каждая строка имеет свой тип; несколько строк могут составлять сообщение. Каждое сообщение начинается со строки с типом start и заканчивается строкой с типом end. PHP может посылать строки с несколькими сообщениями одновременно.

Строка имеет следующий формат:

date  time  host(pidtypemessage-data

date
Дата в формате ISO 8601 (yyyy-mm-dd)
time
Время, включая микросекунды: hh:mm:uuuuuu
host
Имя DNS или IP-адрес хоста, где было сгенерировано сообщение об ошибке.
pid
PID (id процесса) на хосте host процесса исполнившего скрипт PHP в котором произошла ошибка.
type
Тип строки. Сообщает получающей программе как трактовать содержимое строки:

Таблица 0-1. Типы строк отладчика

Тип

Значенне

start Сообщает получающей программе, что в этом месте начинается сообщение. Содержимое строки data содержит тип сообщения об ошибке (см. ниже).
message Сообщение об ошибке.
location Имя файла и номер строки, содержащей ошибку. Первая строка location содержит местоположение, data содержит информацию file:line. Строка location всегда следует после строки message и function.
frames Число кадров в дампе стека. Если их четыре, ожидается информация о четырех уровнях вызываемых функций. Если эта строка отсутствует, глубина предполагается нулевой (ошибка произошла на высшем уровне вложенности).
function Имя функции, содержащей ошибку. Повторяется один раз для каждого уровня в стеке вызовов функции.
end Сообщает получающей программе, что сообщение отладчика закончено.
data
Данные строки.

Таблица 0-2. Типы ошибок отладчика

Отладчик

Внутренняя в PHP

warning E_WARNING
error E_ERROR
parse E_PARSE
notice E_NOTICE
core-error E_CORE_ERROR
core-warning E_CORE_WARNING
unknown (любая другая)
Пример 0-1. Пример сообщения об ошибке

1998-04-05 23:27:400966 lucifer.guardian.no(20481) start: notice
1998-04-05 23:27:400966 lucifer.guardian.no(20481) message: Uninitialized variable
1998-04-05 23:27:400966 lucifer.guardian.no(20481) location: (null):7
1998-04-05 23:27:400966 lucifer.guardian.no(20481) frames: 1
1998-04-05 23:27:400966 lucifer.guardian.no(20481) function: display
1998-04-05 23:27:400966 lucifer.guardian.no(20481) location: /home/ssb/public_html/test.php3:10
1998-04-05 23:27:400966 lucifer.guardian.no(20481) end: notice

[Назад][Содержание]