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

Jobsora


  Опросы

Какие курсы вы бы выбрали для себя?  

Очные
Онлайновые
Платные
Бесплатные
Я и так все знаю

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

1001 и 1 книга  
28.05.2019г.
Просмотров: 1943
Комментарии: 2
Анализ вредоносных программ

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

28.05.2019г.
Просмотров: 1973
Комментарии: 1
Микросервисы и контейнеры Docker

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

28.05.2019г.
Просмотров: 1530
Комментарии: 0
Django 2 в примерах

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

28.05.2019г.
Просмотров: 1117
Комментарии: 0
Введение в анализ алгоритмов

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

27.03.2019г.
Просмотров: 1693
Комментарии: 1
Arduino Uno и Raspberry Pi 3: от схемотехники к интернету вещей

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

Друзья сайта  

Форум системных администраторов  

sysadmins.ru

Электронка - 2020!

 Расширения Р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-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru