Расширения РHP: пять шагов к написанию::Журнал СА 11.2005
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Дата-центры  

Дата-центры: есть ли опасность утечки данных?

Российские компании уже несколько лет испытывают дефицит вычислительных мощностей. Рост числа проектов,

 Читать далее...

Книжная полка  

Защиты много не бывает

Среди книжных новинок издательства «БХВ» есть несколько изданий, посвященных методам социальной инженерии

 Читать далее...

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

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

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6417
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 7120
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4399
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 3086
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3882
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3898
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6388
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3234
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3530
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7364
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10726
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12446
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 14097
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9193
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7142
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5447
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4683
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3497
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3213
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3449
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3091
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Расширения РHP: пять шагов к написанию

Архив номеров / 2005 / Выпуск №11 (36) / Расширения РHP: пять шагов к написанию

Рубрика: Программирование /  Веб-программирование

АЛЕКСАНДР КАЛЕНДАРЕВ

Расширения Р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.


Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru