Если предполагается, что ваша функция принимает переменное количество аргументов,
то рассматриваемые здесь примеры кода могут послужит более или менее оптимальным
решением. Вы должны создать строку, вызывающую zend_get_parameters_ex(),
для каждого возможного количества аргументов, что часто бывает не лучшим решением.
Особое место в системах
мультимедиа занимает использование аудиоаппаратуры
В таком случае вы
можете использовать функцию zend_get_parameters_array_ex(), которая принимает
количество запрашиваемых параметров и массив для их хранения:
zval **parameter_array[4]; /* получить количество аргументов */
argument_count = ZEND_NUM_ARGS(); /* посмотреть, удовлетворяет ли минимальному
запросу (2 аргумента) */ /* и максимальному количеству (4 аргумента) */ if(argument_count
< 2 || argument_count > 5) WRONG_PARAM_COUNT; /* количество аргументов
корректно, теперь запрашиваем их */ if(zend_get_parameters_array_ex(argument_count,
parameter_array) != SUCCESS) WRONG_PARAM_COUNT; |
Сначала
проверяется, находится ли количество аргументов в пределах требуемого диапазона.
После этого zend_get_parameters_array_ex() используется для заполнения
parameter_array правильными указателями на значения аргументов.Пространство
— центральная проблема архитектуры
Очень удачный способ можно найти
в коде, работающем с fsockopen() , находящемся в ext/standard/fsock.c,
как показано в Листинге 9.7. Не волнуйтесь, если вы ещё не знаете всех функций,
использованных в этом исходнике; мы кратко остановимся на них. Белокаменное
зодчество Владимиро-суздальской земли Лесные земли Ростово-Суздальского княжества
долгое время были глухой окраиной Киевской Руси. Первая столица — Ростов — возникла
только в X в. В начале следующего столетия появился Ярославль, основание которого
легенда связывает с Владимиром Мономахом.
Рисунок 33-2. Листинг 9.7. PHP-реализация
переменного количества аргументов в fsockopen()
pval **args[5]; int *sock=emalloc(sizeof(int)); int *sockp; int
arg_count=ARG_COUNT(ht); int socketd = -1; unsigned char udp = 0; struct timeval
timeout = { 60, 0 }; unsigned short portno; unsigned long conv; char *key = NULL;
FLS_FETCH(); if (arg_count > 5 || arg_count < 2 || zend_get_parameters_array_ex(arg_count,args)==FAILURE)
{ CLOSE_SOCK(1); WRONG_PARAM_COUNT; } switch(arg_count) { case 5: convert_to_double_ex(args[4]);
conv = (unsigned long) (Z_DVAL_P(args[4]) * 1000000.0); timeout.tv_sec = conv
/ 1000000; timeout.tv_usec = conv % 1000000; /* fall-through */ case 4: if (!PZVAL_IS_REF(*args[3]))
{ php_error(E_WARNING,"error string argument to fsockopen not passed by reference");
} pval_copy_constructor(*args[3]); ZVAL_EMPTY_STRING(*args[3]); /* fall-through
*/ case 3: if (!PZVAL_IS_REF(*args[2])) { php_error(E_WARNING,"error argument
to fsockopen not passed by reference"); return; } ZVAL_LONG(*args[2], 0); break;
} convert_to_string_ex(args[0]); convert_to_long_ex(args[1]); portno = (unsigned
short) Z_LVAL_P(args[1]); key = emalloc(Z_STRLEN_P(args[0]) + 10); |
Сопротивление материалов
Построение эпюр поперечных сил и изгибающих моментов.
fsockopen()
принимает два, три, четыре или пять аргументов. После обязательного объявления
переменных эта функция проверяет корректность диапазона аргументов. Затем она
использует механизм fall-through в операторе switch() для работы со всеми
аргументами. Оператор switch() начинается с максимального количества
передаваемых аргументов (пять). После этого она автоматически проходит case четырёх
передаваемых аргументов, затем трёх, пропуская обязательное ключевое слово break
на всех этапах. После обработки последнего case функция выходит из оператора switch()
и выполняет минимальный необходимый процессинг, если функция вызвана с двумя аргументами.
get_browser get_cfg_var
get_class get_class_methods
get_class_vars get_current_user
get_declared_classes get_defined_constants
get_defined_functions get_defined_vars
get_extension_funcs get_html_translation_table
get_included_files get_loaded_extensions
get_magic_quotes_gpc get_meta_tags
get_object_vars get_parent_class
get_required_files get_resource_type
getallheaders getcwd
getdate getenv gethostbyaddr
gethostbyname gethostbynamel
getimagesize getlastmod
getmxrr getmygid
getmyinode getmypid
getmyuid getprotobyname
getprotobynumber getrandmax
getrusage getservbyname
getservbyport gettext
gettimeofday gettype
gmdate gmmktime gmp_abs
gmp_add gmp_and gmp_clrbit
gmp_cmp gmp_com gmp_div
gmp_div_q gmp_div_qr
gmp_div_r gmp_divexact
gmp_fact gmp_gcd
gmp_gcdext gmp_hamdist
gmp_init gmp_intval
gmp_invert gmp_jacobi
gmp_legendre gmp_mod
gmp_mul gmp_neg gmp_or
gmp_perfect_square gmp_popcount
gmp_pow gmp_powm
gmp_prob_prime gmp_random
gmp_scan0 gmp_scan1
gmp_setbit gmp_sign
gmp_sqrt gmp_sqrtrm
gmp_strval gmp_sub
gmp_xor gmstrftime
gregoriantojd gzclose
gzcompress gzdeflate
gzencode gzeof gzfile
gzgetc gzgets gzgetss
gzinflate gzopen
gzpassthru gzputs
gzread gzrewind gzseek
gztell gzuncompress
gzwrite Гарантия безопасной записи других параметров
Вы
можете оказаться в ситуации, когда необходимо иметь доступ для записи параметра,
который запрашивается функцией zend_get_parameters_ex(), но не передаётся
по ссылке. В этом случае вы можете использовать макрос SEPARATE_ZVAL,
который выполняет zval-сепарацию в предоставленном контейнере. Вновь генерируемый
zval отсоединяется от внутренних данных и имеет только локальную область
видимости, что означает, что он может быть изменён или уничтожен без глобальных
изменений в контексте скрипта:
zval **parameter; /* запросить параметр */ zend_get_parameters_ex(1,
¶meter); /* на этом этапе <parameter> всё ещё соединён */ /* с
внутренними буферами данных Zend'а */ /* сделать <parameter> write-safe\безопасным
для записи */ SEPARATE_ZVAL(parameter); /* теперь можно безопасно модифицировать
<parameter> */ /* без выполнения глобальных изменений */ |
SEPARATE_ZVAL использует emalloc() для выделения нового
zval-контейнера, и это означает, что даже если вы не зачистите память
самостоятельно, она будет уничтожена автоматически по окончании работы скрипта.
Однако выполнение большого количества вызовов этого макроса без освобождения результирующих
контейнеров использует большой объём вашей RAM-памяти.
- Примечание:
поскольку вы без затруднений можете обойти отсутствие доступа для записи с помощью
"традиционного" API (с zend_get_parameters() и т.д.), этот API выглядит
устаревшим и не обсуждается в этой главе в дальнейшем.
-