АЛЕКСАНДР КАЛЕНДАРЕВ
Расширения РHP: пять шагов к написанию
Это намного проще, чем кажется с первого раза
Расширение в PHP – это набор дополнительных функций, не входящих в ядро PHP-engine. Расширения, как и само ядро PHP-engine, написаны на С, что значительно повышает быстродействие системы, а также позволяет осуществлять доступ к внешним библиотекам и создавать более эффективные веб-приложения. Так как же быстро и надежно разработать расширение?
Вполне закономерный вопрос – зачем нужны дополнительные расширения? Казалось бы, все что нужно скриптовому языку, в PHP уже охвачено. В последний дистрибутив четвертой версии входит 74 РНР-расширения. На официальном сайте www.php.net есть раздел, специально посвященный этой теме: www.pecl.php.net. На данноме ресурсе находится библиотека исходных текстов еще 132х дополнительных расширений. Не стоит забывать, что PHP относится к языкам интерпритируемого типа, т.е. каждая команда языка интерпритируется во время исполнения, что заметно проигрывает в скорости языкам компилируемого типа. Практика показывает, что для ускорения части функционала (написание функций с использованием битовых операций, т.к. они медленно отрабатываются на PHP и очень замедляют работу скрипта) приходится писать расширения, а также если необходимо обратиться к уже существующим C-библиотекам (например, криптографические или ГИСбиблиотеки). Наверное, у каждого из вас найдется своя причина, чтобы написать новое расширение.
Данная статья поможет вам понять основы построения расширений и освоить технику написания расширений под *nix-системы. Написание расширений под Windows отличается только способом компилирования и обращения к внешним библиотекам.
В двух словах, под расширением понимается часть PHP-функций, которые реализованы в виде отдельного модуля, написанного на С. Данные функции могут либо подключаться, как внешний модуль, либо скомпилированы статически в исходный код PHP. Простым примером расширения является модуль php_mysql, который реализует интерфейс с БД MySql. Интерфейсом взаимодействия между внешними функциями и ядром PHP (PHP-engine) является PHP API, а начиная с версии 4.1.0 в качестве API используется Zend API.
Шаг первый
Создаем шаблон расширения (скелетон)
Для написания и компиляции расширений вам понадобится дистрибутив PHP. Первоначально входим в директорию ext, в которой находятся папки с исходными кодами всех расширений. Внутри папки ext находится папка skeleton, которая представляет собой заготовку или шаблон для написания расширений. В принципе, данная папка нам может и не понадобиться. Процесс написания шаблонов уже автоматизирован, нам остается только запустить скрипт генерации шаблона расширения или, как его называют разработчики, «скелетона». Запуск скрипта без параметров приведет к выдаче на консоль перечня всех параметров:
# ./ext_skel
./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]] [--skel=dir] [--full-xml] [--no-help]
--extname=module module is the name of your extension
--proto=file file contains prototypes of functions to create
--stubs=file generate only function stubs in file
--xml generate xml documentation to be added to phpdoc-cvs
--skel=dir path to the skeleton directory
--full-xml generate xml documentation for a self-contained extension
(not yet implemented)
--no-help don’t try to be nice and create comments in the code
and helper functions to test if the module compiled
|
Для создания модуля первоночально необходимо запустить скрипт с параметром:
# ./ext_skel --extname=module
После отработки скрипта будет создана директория test с файлами шаблона («скелетон») модуля.
# ./ext_skel --extname=test
Creating directory test
Creating basic files: config.m4 .cvsignore test.c php_test.h CREDITS EXPERIMENTAL tests/001.phpt test.php [done].
To use your new extension, you will have to execute the following steps:
1. $ cd ..
2. $ vi ext/test/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-test
5. $ make
6. $ ./php -f ext/test/test.php
7. $ vi ext/test/test.c
8. $ make
Repeat steps 3-6 until you are satisfied with ext/test/config.m4 and step 6 confirms that your module is compiled
into PHP. Then, start writing code and repeat the last two steps as often as necessary.
|
Мы с вами только что создали шаблон нашего первого расширения. В поддиректории test находятся следующие сгенерированные файлы:
- -rw-r--r-- 1 4 Nov 2 00:01 CREDITS – текстовый, информационный.
- -rw-r--r-- 1 0 Nov 2 00:01 EXPERIMENTAL – текстовый, информационный.
- -rw-r--r-- 1 1964 Nov 2 00:01 config.m4 – шаблон конфигурационного файла.
- -rw-r--r-- 1 2707 Nov 2 00:01 php_test.h – шаблон файла заголовков (Н-файл).
- -rw-r--r-- 1 5379 Nov 2 00:01 test.c – шаблон исходного файла на С.
- -rw-r--r-- 1 469 Nov 2 00:01 test.php – шаблон тестового файла.
- drwxr-xr-x 2 0 Nov 2 00:01 tests – директория для регрессионных тестов.
Шаг второй
Настраиваем конфигурацию config.m4
Следующий шаг в настройке нашего шаблона – это задание конфигурационного файла. Модуль будущего расширения может быть скомпилирован либо как внешний so-модуль (shared object), либо статически, как часть php. Для отладки расширения удобнее его собирать как внешний модуль. Достоинство такого подхода в том, что при этом не нужно пересобирать PHP полностью, а достаточно лишь отдельно перекомпилировать только одно исходное расширение.
Если модуль собирается статически, то при конфигурировании ядра php необходимо задать ключи: ./configure --with-test или ./configure --enable-test.
Как вы видите (пример config.m расположен ниже), большинство директив в файле config.m закомментировано символами dnl. Вам необходимо раскомментировать те строки, которые указывают, в каком качестве (динамического или статического модуля) в дальнейшем будет использовано расширение. В случае если вы будете конфигурировать наш модуль как статический, то необходимо раскомментировать строки 10 и 12 с описанием макроса PHP_ARG_WITH.
Для динамического модуля необходимо раскомментировать строчки с описанием макроса PHP_ARG_ENABLE (это будут строки 16 и 18). Данный макрос устанавливает соответствия переменным для макроса PHP_NEW_EXTENSION как компиляция динамического модуля (shared objects).
Первый аргумент макроса PHP_NEW_EXTENSION задает имя расширения. Второй аргумент – файл источника (исходный файл описания с-функций), и третий – это имя внутренней переменной, которая используется в макросах.
Ниже будет приведен пример config.m4 для конфигурирования расширения под компиляцию динамического модуля. Раскомментированные строки отмечены красным шрифтом.
1 dnl $Id$
2 dnl config.m4 for extension test
3
4 dnl Comments in this file start with the string 'dnl'.
5 dnl Remove where necessary. This file will not work
6 dnl without editing.
7
8 dnl If your extension references something external, use with:
9
10 dnl PHP_ARG_WITH(test, for test support,
11 dnl Make sure that the comment is aligned:
12 dnl [ --with-test Include test support])
13
14 dnl Otherwise use enable:
15
16 PHP_ARG_ENABLE(test, whether to enable test support,
17 dnl Make sure that the comment is aligned:
18 [ --enable-test Enable test support] )
19
20 if test "$PHP_TEST" != "no"; then
21 dnl Write more examples of tests here...
22
23 dnl # --with-test -> check with-path
24 dnl SEARCH_PATH="/usr/local /usr" # you might want to change this
25 dnl SEARCH_FOR="/include/test.h" # you most likely want to change this
26 dnl if test -r $PHP_TEST/; then # path given as parameter
27 dnl TEST_DIR=$PHP_TEST
28 dnl else # search default path list
29 dnl AC_MSG_CHECKING([for test files in default path])
30 dnl for i in $SEARCH_PATH ; do
31 dnl if test -r $i/$SEARCH_FOR; then
32 dnl TEST_DIR=$i
33 dnl AC_MSG_RESULT(found in $i)
34 dnl fi
35 dnl done
36 dnl fi
37 dnl
38 dnl if test -z "$TEST_DIR"; then
39 dnl AC_MSG_RESULT([not found])
40 dnl AC_MSG_ERROR([Please reinstall the test distribution])
41 dnl fi
42
43 dnl # --with-test -> add include path
44 dnl PHP_ADD_INCLUDE($TEST_DIR/include)
45
46 dnl # --with-test -> check for lib and symbol presence
47 dnl LIBNAME=test # you may want to change this
48 dnl LIBSYMBOL=test # you most likely want to change this
49
50 dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
51 dnl [
52 dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $TEST_DIR/lib, TEST_SHARED_LIBADD)
53 dnl AC_DEFINE(HAVE_TESTLIB,1,[ ])
54 dnl ],[
55 dnl AC_MSG_ERROR([wrong test lib version or lib not found])
56 dnl ],[
57 dnl -L$TEST_DIR/lib -lm -ldl
58 dnl ])
59 dnl
60 dnl PHP_SUBST(TEST_SHARED_LIBADD)
61
62 PHP_NEW_EXTENSION(test, test.c, $ext_shared)
63 fi
Для осуществления некоторых условий проверок (например, на наличие некоторых необходимых библиотек или соответствие допустимых версий) для положительной компиляции на этапе конфигурирования, раскомментируйте соответствующие строчки с 20 по 60.
Шаг третий
Компиляция
Как уже упоминалось, компиляция нашего расширения может быть как в модуль, который является частью самого PHP, так и во внешний модуль, подгружаемый во время исполнения.
Для статической компиляции необходимо в домашней директории php выполнить команды:
# ./buildconf
# ./configure --enable-test [прочие опции]
# make
# make install
Как упоминалось выше, для отладки лучше используйте компиляцию расширения как внешнего модуля (test.so). Для этого необходимо выполнить следующие команды:
# cd test
# phpize
# ./configure --enable-test=shared
# make
# make install
По окончании работы скрипта появляется директория modules, в которой должен быть файл test.so. Если во время компиляции происходят какие-то ошибки, то это, как правило, связанно с тем, что некоторые пути не прописаны, или какие-то библиотеки не найдены.
Проверка
Как правило, если все удачно скомпилировано, то можно сразу же осуществить тестовую проверку. Если на сервере установлена cli-версия PHP (версия PHP для командной строки), то вы можете прямо из консоли проверить, как скомпилировалось наше расширение.
# php test.php
Warning: dl(): Unable to load dynamic library "./test.so" - ./test.so: cannot open shared object file:
No such file or directory in /usr/local/src/php-4.4.0/ext/test/test.php on line 4 Functions available
in the test extension:
Warning: Invalid argument supplied for foreach() in /usr/local/src/php-4.4.0/ext/test/test.php on line 9
Module test is not compiled into PHP
|
Не стоит сразу так расстраиваться, php просто не нашел наш модуль, т.к. модуль лежит в поддиректории modules, а php осуществляет поиск при отсутствии полного пути в текущей директории.
Для того чтобы проверить работу, достаточно лишь скопировать или перенести скомпилированный файл модуля в директорию самого расширения.
# cd modules
# cp * ..
# cd ..
# php test.php
Functions available in the test extension:
confirm_test_compiled
Congratulations! You have successfully modified ext/test/config.m4.
Module test is now compiled into PHP.
|
Как вы видите, при запуске наш тестовый модуль выводит нам поздравление, что он успешно скомпилирован.
Если cli-версия PHP отсутствует, то необходимо наш модуль переписать в директорию, определенную в php.ini (секция Paths and Directories) как директория для расширений, а также дописать строчку, которая определяет подключение нашего расширения (строка выделена красным шрифтом).
Строки в php.ini:
; UNIX: "/path1:/path2"
extension_dir = ".;/usr/local/php/extension"
; Dynamic Extensions ;
extension=test.so
Необходимо отметить, что при перекомпиляции модуля достаточно выполнить только одну команду make.
Шаг четвертый
Добавляем новую функцию
Вы научились компилировать шаблон php-расширения. Но при разработке модуля, как правило, необходимо использовать множество функций.
Прежде чем рассмотреть, как добавлять новую функцию, перейдем к рассмотрению сгенерированного кода на С (файл test.с) :
1 #include "php.h"
2 #include "php_ini.h"
3 #include "ext/standard/info.h"
4 #include "php_test.h"
5
6 /* If you declare any globals in php_test.h
7 uncomment this: ZEND_DECLARE_MODULE_GLOBALS(test)
8 */
9
10 /* True global resources – no need for thread safety here */
11 static int le_test;
12
13 /* {{{ test_functions[]
14* Every user visible function must have an entry in test_functions[].
15 */
16 function_entry test_functions[] = {
17 PHP_FE(confirm_test_compiled, NULL) /* For testing, remove later. */
18 {NULL, NULL, NULL} /* Must be the last line in test_functions[] */
19 };
20 /* }}} */
21
22 /* {{{ test_module_entry
23 */
24 zend_module_entry test_module_entry = {
25 #if ZEND_MODULE_API_NO >= 20010901
26 STANDARD_MODULE_HEADER,
27 #endif
28 "test",
29 test_functions,
30 PHP_MINIT(test),
31 PHP_MSHUTDOWN(test),
32 PHP_RINIT(test), /* Replace with NULL if there’s nothing to do at request start */
33 PHP_RSHUTDOWN(test), /* Replace with NULL if there’s nothing to do at request end */
34 PHP_MINFO(test),
35 #if ZEND_MODULE_API_NO >= 20010901
36 "0.1", /* Replace with version number for your extension */
37 #endif
38 STANDARD_MODULE_PROPERTIES
39 };
40 /* }}} */
41
42 #ifdef COMPILE_DL_TEST
43 ZEND_GET_MODULE(test)
44 #endif
45 /* {{{ PHP_INI
46 */
47 /* Remove comments and fill if you need to have entries in php.ini
48 PHP_INI_BEGIN()
49 STD_PHP_INI_ENTRY("test.global_value", "42", PHP_INI_ALL, OnUpdateInt, global_value, zend_test_globals, test_globals)
50 STD_PHP_INI_ENTRY("test.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_test_globals, test_globals)
51 PHP_INI_END()
52 */
53 /* }}} */
54
55 /* {{{ php_test_init_globals */
56 /* Uncomment this function if you have INI entries
57 static void php_test_init_globals (zend_test_globals *test_globals)
58 {
59 test_globals->global_value = 0;
60 test_globals->global_string = NULL;
61 }
62 */
63 /* }}} */
64
65 /* {{{ PHP_MINIT_FUNCTION */
66 PHP_MINIT_FUNCTION(test)
67 {
68 /* If you have INI entries, uncomment these lines
69 ZEND_INIT_MODULE_GLOBALS (test, php_test_init_globals, NULL);
70 REGISTER_INI_ENTRIES();
71 */
72 return SUCCESS;
73 }
74 /* }}} */
75
76 /* {{{ PHP_MSHUTDOWN_FUNCTION
77 */
78 PHP_MSHUTDOWN_FUNCTION(test)
79 {
80 /* uncomment this line if you have INI entries
81 UNREGISTER_INI_ENTRIES();
82 */
83 return SUCCESS;
84 }
85 /* }}} */
86
87 /* Remove if there’s nothing to do at request start */
88 /* {{{ PHP_RINIT_FUNCTION */
89 PHP_RINIT_FUNCTION(test)
90 {
91 return SUCCESS;
92 }
93 /* }}} */
94
95 /* Remove if there’s nothing to do at request end */
96 /* {{{ PHP_RSHUTDOWN_FUNCTION */
97 PHP_RSHUTDOWN_FUNCTION(test)
98 {
99 return SUCCESS;
100 }
101 /* }}} */
102
103 /* {{{ PHP_MINFO_FUNCTION */
104 PHP_MINFO_FUNCTION(test)
105 {
106 php_info_print_table_start();
107 php_info_print_table_header(2, "test support#, "enabled#);
108 php_info_print_table_end();
109
110 /* Remove comments if you have entries in php.ini
111 DISPLAY_INI_ENTRIES(); */
112 }
113 /* }}} */
114
115
116 /* Remove the following function when you have succesfully
117 modified config.m4 so that your module can be compiled
118 into PHP, it exists only for testing purposes. */
119
120 /* Every user-visible function in PHP should document itself in the source */
121 /* {{{ proto string confirm_test_compiled(string arg)
122 Return a string to confirm that the module is compiled in */
123 PHP_FUNCTION(confirm_test_compiled)
124 {
125 char *arg = NULL;
126 int arg_len, len;
127 char string[256];
128
129 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
130 return;
131 }
132
133 len = sprintf(string, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "test", arg);
134 RETURN_STRINGL(string, len, 1);
135 }
136 /* }}} */
Рассмотрим более подробно содержание файла test.с. Все PHP-модули имеют общую структуру:
- блок включения заголовков (макросы, определения API, внешние библиотеки);
- С-объявление функции экспорта;
- блок объявлений функций (PHP) Zend;
- блок объявлений модуля (PHP) Zend;
- реализация get_module();
- реализация всех экспортных функций.
Объявление функции экспорта (строки) находится в заголовочном h-файле (php_test.h):
/* For testing, remove later. */
PHP_FUNCTION(confirm_test_compiled);
В нашем случае это только одна функция, которая была сгенерирована скриптом «скелетона»: confirm_test_compiled().
Если вам необходимо добавить новую функцию, то для этого добавляйте макрос ее описания в заголовочный файл php_test.h. Например, если вы хотите добавить новую функцию add_string(), то должны дополнить заголовочный файл (php_test.h) макросом описания экспортируемой функции (красным цветом помечен добавленный текст) :
PHP_FUNCTION(confirm_test_compiled);
/* добавляем объявление экспортируемой функции */
PHP_FUNCTION(add_string);
Блок объявлений функций Zend в коде (файл test.с) строки 16-19. Для каждой видимой для PHP-функции необходимо описывать ее в function_entry. Для того чтобы добавить новую функцию, необходимо расширить описание структуры (красным цветом помечен добавленный текст):
16 function_entry test_functions[] = {
17 PHP_FE(confirm_test_compiled, NULL) PHP_FE(add_string, NULL) /* добавляем объявление новой функций */
18 {NULL, NULL, NULL} /* эта строка всегда должна быть последней в описании*/
19 };
Макрос PHP_FE(name,arg_types) определяет имя точки входа в описании function_entry.
Если уже реализовано описание функции и мы хотим дополнить API нашего расширения еще одной точкой входа, т.е. создать псевдоним функции (или alias), тогда мы определяем alias с помощью макроса: PHP_FALIAS(name,alias,arg_types).
Блок объявлений модуля Zend запоминается в структуре zend_module_entry test_module_entry{} (строки 24-40) и содержит всю информацию о содержании нашего модуля (расширения). Как правило, нам изменять код в данной структуре не приходится.
Данные структуры test_module_entry:
28 "test" , /* имя модуля */.
29 test_functions, /* ссылка на блок объявлений функций, стр 16 */
30 PHP_MINIT(test), /* ссылка на описание функции инициализации модуля, стр 65-74 */
31 PHP_MSHUTDOWN(test), /* ссылка на описание функции деинициализации модуля, стр 76-85 */
32 PHP_RINIT(test), /* ссылка на описание функции при инициализации страницы, стр 88-93 */
33 PHP_RSHUTDOWN(test), /* ссылка на описание функции при деинициализации страницы, стр 96-101 */
34 PHP_MINFO(test), ), /* ссылка на описание функции, которая выдает информацию для phpinfo() */
35 #if ZEND_MODULE_API_NO >= 20010901
36 "0.1", ) /* Номер версии нашего расширения */
37 #endif
Описание тела самой функции определяется макросом PHP_FUNCTION (name). Описание функции confirm_test_compiled() определено в строчках 121-136. Если вы хотите добавить новую функцию add_string(), то необходмио скопировать строчки 121-136 ниже и изменить имя функции и содержание того, что она должна выводить (красным цветом помечен измененный текст):
/* {{{ proto string confirm_test_compiled(string arg) */
PHP_FUNCTION(add_string)
{
char *arg = NULL;
int arg_len, len;
char string[256];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE)
{ return; }
len = sprintf(string, "Congratulations! You have successfully new function ");
RETURN_STRINGL(string, len, 1);
}
/* }}} */
Нам остается повторить шаг 3 – компиляцию. Надеюсь, она прошла удачно.
Далее немного изменим файл test.php:
<?
print PHP_SHLIB_SUFFIX;
if(!extension_loaded('test')) {
dl('test.' . PHP_SHLIB_SUFFIX);
}
$module = 'test';
$functions = get_extension_funcs($module);
echo "Functions available in the test extension:<br>\n";
foreach($functions as $func) {
echo $func."<br>\n";
}
echo "<br>\n";
print add_string($module);
?>
При верной компиляции вызов функции add_string($module) выдаст перечень доступных функций и свои поздравления: «Congratulations! You have successfully new function» – это и есть поздравления.
# php test.php
Functions available in the test extension:
confirm_test_compiled
add_string
Congratulations! You have successfully new function
|
Шаг пятый
Передача параметров
Вы научились создавать шаблон модуля, добавлять в него функции. Конечно, функции нужны для того, чтоб что-то вычислять или производить какие-то действия с данными. Для этого в функцию необходимо передать какой-нибудь список параметров и получить результат.
Для передачи параметров из PHP в модуль используются макросы. Макрос ZEND_NUM_ARGS() возвращает количество аргументов, переданное PHP-скриптом в модуль.
Можно, например, для контроля количества аргументов использовать следующий код:
if(ZEND_NUM_ARGS() != 2) WRONG_PARAM_COUNT;
Необходимо заметить, что макрос WRONG_PARAM_COUNT определен в $PHP_HOME/Zend/zend_API.h, поэтому необходимо добавить заголовочный файл:
#include "zend_API.h"
При выполнении макроса WRONG_PARAM_COUNT будет выдано следующее предупреждение:
Warning Wrong parameter count for module test()in /usr/local/src/php-4.4.0/ext/test/test.php on line 4 |
Макрос zend_parse_parameters производит анализ (проверку) параметров.
int zend_parse_parameters(
/* количество аргументов. Может быть ZEND_NUM_ARGS() */
int num_args TSRMLS_DC,
char *type_spec, /* спецификация */
/* объявление аргумента в соответствии с его типом*/
arg_type arg,
...);
Рассмотрим наш пример (файл test.с), строка 129.
В данном макросе для определения первого аргумента – количество переданных параметров – используется ZEND_NUM_ARGS().
Вторым параметром стоит спецификация «s», которая указывает на тип передаваемого аргумента – строка. Третьим и четвертым параметрами являются значения переменных, в которые передается содержание строки и ее длины.
Спецификация определяется символами типа и спецсимволами. Символы типа определяют тип переменной, притом первый символ типа определяет тип первого аргумента, второй – второго и так далее…
В PHP API определены следующие символы типа:
- l – long;
- d – double;
- s – string (с заключающим нетерминальным ‘?’) и его длина;
- b – boolean;
- r – ресурс;
- a – массив;
- o – объект;
- O – объект, определенный как точка входа zval*;
- z – Zend – объект(zval*).
Ресурс, массив и объект должны иметь тип zval*.
Специальные символы дополняют спецификацию типов:
- | – определяет границу между обязательными и необязательными (опциональными) параметрами. Необязательные параметры в этом случае инициализируются значениями по умолчанию.
- / – при анализе параметра вызывает функцию SEPARATE_ZVAL_IF_NOT_REF(), которая предоставляет копию параметра, если он не является ссылкой.
- ! – следующий параметр может специфицировать тип или значение NULL (применимо только к типам a, o, O, r и z). Если будет значение NULL, то будет установлен указатель на переменную параметра в NULL.
Примеры спецификаций:
- «ssl|a» – передается три обязательных параметра («string», «string», «long») и один опциональный, тип «array».
- «a/» – передается раздельный массив.
В качестве примера изменим строку в файле test.php:
<?
if(!extension_loaded('test')) {
dl('test.' . PHP_SHLIB_SUFFIX);
}
$module = 'test';
$i = 12;
print add_string($module, $i );
?>
А в файле test.с изменим тело функции add_string:
/* {{{ proto string confirm_test_compiled(string arg) */
PHP_FUNCTION(add_string)
{
char *arg = NULL;
int arg_len, len;
int i = 0 ;
char string[256];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &arg, &arg_len, ) == FAILURE)
{ return; }
len = sprintf(string, "Congratulations! You pass parameters string: %s <br>\n integer: %l ", arg, i );
RETURN_STRINGL(string, len, 1);
}
/* }}} */
Запуск тестового скрипта выдаст следующие результаты:
# php test.php
Congratulations! You pass parameters string: test
Integer: 12
|
В случае если на этапе обработки параметров вычисляются какие-либо ошибки или несоответствия, то можно использовать макрос:
php_error(
E_WARNING, /* тип сообщения, в данном случае WARNING,
для ошибки тип E_ERROR */
message , /* сообщение */
/* имя вызываемой функци */
[ get_active_function_name( TSRMLS_C )]
);
И последнее, без чего не было бы логического завершения, так это возвращаемые значения функций. Каждая определенная в РНР функция может что-либо возвращать: в нашем примере файл test.с возвращает в строке 134 строковое значение (строку string_value длиной lenght_string) используя Макрос RETURN_STRINGL(string_value, lenght_string, duplicate_flag).
У всех макросов тип возвращаемого значения понятен из их названия. Например, макрос RETURN_LONG(long_value) возвращает значение, определенное типом long.
Существуют следующие макросы:
- RETURN_BOOL (bool)
- RETURN_NULL
- RETURN_FALSE
- RETURN_TRUE
- RETURN_DOUBLE(double)
- RETURN_STRING(string_value, duplicate_flag)
- RETURN_EMPTY_STRING()
- RETURN_RESOURCE (resource)
Следует отметить отличие макроса RETURN_STRINGL() от RETURN_STRING() в том, что первый макрос работает быстрее второго за счет явного определения количества выводимых символов.
Вместо заключения
В принципе данных знаний вам будет достаточно для написания простых функций, которые можно использовать в РНР. Более подробную информацию по данной теме можно найти на официальном сайте: http://ru.php.net/streams или http://zend.com/apidoc/zend.php.