Продолжаем знакомиться с тем, как же все таки писать свои расширения PHP…
Сегодня мы узнаем как сделать функцию которая принимает аргументы, и работает с ними. За основу возьмем тот же код который был в прошлой статье, и немного доработаем его.
Объявление функций
В этой статье мы объявим две новых функции, hello_php ($who); и hello_php2($who, $howMany = 1);. Перейдем сразу к примеру:
PHP_FUNCTION(hello_php); ZEND_BEGIN_ARG_INFO(arginfo_hello_php, 0) ZEND_ARG_INFO(0, who) ZEND_END_ARG_INFO() PHP_FUNCTION(hello_php2); ZEND_BEGIN_ARG_INFO(arginfo_hello_php2, 0) ZEND_ARG_INFO(0, who) ZEND_ARG_INFO(0, howMany) ZEND_END_ARG_INFO()
Тут мы используем точно такую же декларацию функций с помощью макроса PHP_FUNCTION (func), но к этому так добавляются макросы ZEND_BEGIN_ARG_INFO (name, pass_by_ref) который открывает область декларации аргументов, ZEND_END_ARG_INFO () — который завершает эту область, и ZEND_ARG_INFO (pass_by_ref, name) — который собственно декларирует аргумент.
Помимо ZEND_ARG_INFO () есть еще макросы:
- ZEND_ARG_OBJ_INFO (pass_by_ref, name, classname, allow_null) для указания typehint’а в виде имени класса
- ZEND_ARG_TYPE_INFO (pass_by_ref, name, type_hint, allow_null) для указания иного typehint
- ZEND_ARG_ARRAY_INFO (pass_by_ref, name, allow_null) для указания array‐typehint
Но о них мы поговорим в следующий раз.
После декларации функций мы помещаем их в массив с списком функций (ваш КО) — zend_function_entry my_functions:
static zend_function_entry my_functions[] = { PHP_FE(hello_php, arginfo_hello_php) PHP_FE(hello_php2, arginfo_hello_php2) {NULL, NULL, NULL} };
В прошлой статье мы в качестве второго аргумента для макроса PHP_FE () указывали NULL, сейчас же — массив с аргументами для нужной функции.
Реализация
С декларацией вроде ничего сложного, осталось только написать реализацию, которая как ни странно не сложнее декларации:
// implementation of a custom hello_php() PHP_FUNCTION(hello_php) { char text[1024]; char *who; int who_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &who, &who_len) == FAILURE) { return; } sprintf(text, "Hello %s ", who); RETURN_STRING(text, 1); } // implementation of a custom hello_php2() PHP_FUNCTION(hello_php2) { char text[1024]; char *who; long howMany = 1; int who_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &who, &who_len, &howMany) == FAILURE) { return; } sprintf(text, "Hello %d %s ", howMany, who); RETURN_STRING(text, 1); }
Описания в этом коде достойна только функция zend_parse_parameters ().
Функция zend_parse_parameters (int num_args TSRMLS_DC, const char *type_spec, …) в качестве аргументов принимает количество аргументов, строку с описанием типов всех аргументов, ну и ссылки на переменные в которые необходимо получить. При использовании данной функции в качестве первого аргумента передается макрос ZEND_NUM_ARGS () который судя по всему возвращает количество аргументов для данной функции, а так же макрос TSRMLS_CC (еще есть TSRMLS_C, TSRMLS_DC, TSRMLS_D), но для чего он нужен — я так и не понял :).
В качестве описания типов аргументов используется строка, например — «s» указывает что мы хотим получить строку, и передаем ссылку на char* и int (в который будет помещена длина строки), а «s|l» указывает на то, что мы хотим получить в качестве первого аргумента строку, а в качестве второго — long, который ко всему прочему может быть и не указан, т.е. будет являться не обязательным аргументом. Список поддерживаемых типов и флагов:
- l — long (long)
- d — double (double)
- b — boolean (zend_bool)
- a — array (zval*)
- o — object (zval*)
- O — object (zval*, zend_class_entry)
- s — string (char*, int)
- r — resource (zval*)
- z — zval (zval*)
- Z zval‐ref (zval**)
- | — все что после этого — не обязательные аргументы
- / — ?
- ! — ?
Также, функция zend_parse_parameters возвращает одно из двух возможных значений — SUCCESS и FAILED, что есть что — понять не сложно.
Заключение
Вот мы и познакомились с тем, как сделать функцию которая будет принимать аргументы.
Полный исходник можно взять там => hello_world.c, а так же можно почитать этот мануал, который мне частично помог.
P.S. Добра вам :)