Разработка расширений php: аргументы функций

Продолжаем знакомиться с тем, как же все таки писать свои расширения 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. Добра вам :)

comments powered by Disqus