Доступ к аргументам Учебник PHP

Для доступа к аргументам необходимо иметь для каждого аргумента ясно определённый тип. Предельно динамичная природа PHP позволяет прибегать к некоторым трюкам. Поскольку PHP никогда не делает никакой проверки типа, вызыватель может передавать в функции любой вид данных, хотите вы этого или нет. Если вы ожидаете integer, например, вызыватель может передать массив, и наоборот - PHP этого не заметит. Внешние запоминающие устройства (ВЗУ)

Чтобы работать в этих условиях, вы должны использовать набор API-функций для форсирования конвертации типов каждого передаваемого аргумента (см. Таблицу 9.4). Крестово-купольные храмы

Примечание: Все функции конвертации ожидают в качестве параметра **zval.

Рисунок 33-3. Таблица 9.4. Функции конвертации аргументов
ФункцияОписание
convert_to_boolean_ex()Форсирует конвертацию в Boolean. Boolean-значения не изменяются. Long, double и string, содержащие значения 0 и NULL, дают Boolean 0 (FALSE). Массивы и объекты конвертируются на основе количества вхождений или свойств, соответственно. Пустые массивы и объекты конвертируются в FALSE; другие - в TRUE. Все другие значения дают Boolean 1 (TRUE).
convert_to_long_ex()Форсирует конвертацию в long, целочисленный тип по умолчанию. NULL, Boolean, ресурсы и, разумеется, long-значения не изменяются. Double усекаются. String, содержащие integer, конвертируются в соответствующие числовые представления, иначе - дают 0. Массивы и объекты конвертируются в 0, если пустые, иначе - в 1.
convert_to_double_ex()Форсирует конвертацию в double, тип по умолчанию с плавающей точкой. NULL, Boolean, ресурсы, long и double не изменяются. String, содержащие integer, конвертируются в соответствующие числовые представления, иначе - дают 0.0. Массивы и объекты конвертируются в 0.0, если пустые, иначе - в 1.0. Сопротивление материалов Растяжение и сжатие Растяжением или сжатием называют вид нагружения, при котором в поперечном сечении бруса возникает только один внутренний силовой фактор — продольная сила.
convert_to_string_ex()Форсирует конвертацию в string. String остаются без изменений. NULL конвертируются в пустые строки. Boolean TRUE конвертируются в "1", иначе дают пустую строку. Long и double конвертируются в their соответствующие строковые представления. Массивы конвертируются в строку "Array", а объекты - в строку "Object".
convert_to_array_ex(value)Форсирует конвертацию в массив. Массивы остаются без изменений. Объекты конвертируются в массив с присвоением всех свойств таблице массива. Имена свойств используются как ключи, содержание свойств - как значения. NULL конвертируются в пустой массив. Все другие значения конвертируются в массив, который содержит специфическое исходное значение в элементе с ключом 0. Искусство Кореи Корея, или Чосон (Страна Утреннего Спокойствия), расположена на Корейском полуострове. Природа этой страны, с трёх сторон омываемой морями, разнообразна и красива. Цветущий край, изобилующий богатствами - золотом, самоцветами, мрамором, — издавна привлекал соседей.
convert_to_object_ex(value)Форсирует конвертацию в объект. Объекты остаются без изменений. NULL конвертируются в пустой объект. Массивы конвертируются в объекты с ключами как свойствами и значениями свойств как содержимым свойств. Все другие типы дают объект со свойством scalar, имеющим исходное значение в качестве содержимого.
convert_to_null_ex(value)Форсирует типы в NULL, что означает пустой.

Работа с аргументами, передаваемыми по ссылке

Если ваша функция принимает передаваемые по ссылке аргументы, которые вы намереваетесь изменять, вы должны предпринять некоторые меры предосторожности.

Мы ещё не говорили, что при указанных обстоятельствах вы не имеете доступа для записи любого параметра функции назначения zval-контейнера, передаваемого (параметр) вам. Конечно, вы можете изменять любой zval-контейнер, который создали внутри вашей функции, но вы обязаны не изменять любые zvals, которые ссылаются на внутренние Zend-данные!

Мы обсудили только так называемый *_ex() API. Вы могли заметить, что API-функции, использованные нами, вызываются zend_get_parameters_ex(), вместо zend_get_parameters(), convert_to_long_ex() вместо convert_to_long(), etc. Функции *_ex() образуют так называемый новый "расширенный/extended" Zend API. Они дают незначительное увеличение скорости по сравнению со старым API, но предназначаются главным образом для предоставления доступа "только-для-чтения".

Поскольку Zend работает внутренне со ссылками, разные переменные могут ссылаться на одно значение. Доступ для записи в zval-контейнер требует, чтобы этот контейнер содержал изолированное значение, то есть значение, на которое нет ссылок из других контейнеров. Если бы на zval-контейнер имелись ссылки из других контейнеров и вы изменили бы zval, на который ссылаются, вы могли бы автоматически изменять содержимое других контейнеров, ссылаясь на данный zval (поскольку они просто указывали бы на изменённое значение и изменяли бы таким образом свои собственные значения).

zend_get_parameters_ex() не отслеживает такую ситуацию, а просто возвращает указатель на желаемые zval-контейнеры, независимо от того, состоят они из ссылок или нет. Соответствующая ему функция в традиционном API, zend_get_parameters(), немедленно проверяет значения по ссылкам. Если он обнаруживает ссылку, он создаёт новый изолированный zval-контейнер; копирует ссылочные данные в это вновь выделенное пространство; затем возвращает указатель на это новое изолированное значение.

Эта акция называется zvalseparation\сепарация zval (или zval separation). Поскольку *_ex() API не выполняет zval separation, он работает быстрее, отменяя за это же время доступ для записи.

Однако для изменения параметров доступ для записи необходим. Zend обрабатывает эту ситуацию специальным способом: При передаче параметра в функцию по ссылке, он выполняет автоматическую zval-сепарацию. Это означает, что всякий раз, когда вызываете функцию вроде этой в PHP, Zend автоматически будет гарантировать, что этот $parameter передаётся как изолированное значение с переводом его в состояние write-safe/безопасной записи:
my_function(&$parameter);

Но это не так в случае в регулярными параметрами! Все другие параметры, которые не передаются по ссылке, находятся в состоянии read-only/только-для-чтения.

Это требует, чтобы вы гарантировали, что вы реально работаете со ссылкой - иначе вы можете получить нежелательный результат. Для проверки передачи параметра по ссылке вы можете использовать макрос PZVAL_IS_REF. Этот макрос принимает zval* и проверяет, является он ссылкой или нет. Примеры даны в Листинге 9.6 и на Рисунке 9.9 (см. на CD-ROM полный исходник).

Старый способ запроса аргументов

Не рекомендуемый API разбора параметров: Этот API не рекомендуется использовать. Вместо него имеется новый ZEND API разбора параметров.

После проверки количества аргументов вам необходимо получить доступ к самим аргументам. Это делается с помощью zend_get_parameters_ex():
zval **parameter; if(zend_get_parameters_ex(1, &parameter) 
!= SUCCESS) WRONG_PARAM_COUNT;

Все аргументы хранятся в контейнере zval, на который нужно указать дважды. Показанный код пытается получить один аргумент и сделать его доступным нам через указатель parameter.

zend_get_parameters_ex() принимает как минимум два аргумента. Первый аргумент это количество получаемых аргументов (которое должно совпадать с количеством аргументов, с которыми функция вызывается; именно поэтому важно проверять корректность синтаксиса вызова). Второй аргумент (и все последующие аргументы) это указатели на указатели на указатели на zval'ы. (Малопонятно, не правда ли?) Все эти указатели необходимы, поскольку Zend работает внутренне с **zval; для уточнения местного **zval в нашей функции, zend_get_parameters_ex() требует указатель на него.

return-значением zend_get_parameters_ex() может быть SUCCESS или FAILURE, указывая на успех или неудачу процессинга аргументов. Неудача чаще всего связана с некорректным количеством специфицированных аргументов, и тогда вы вы должны выйти с WRONG_PARAM_COUNT.

Для получения более одного аргумента вы можете использовать похожий код:
zval **param1, **param2, **param3, **param4; if(zend_get_parameters_ex(4, 
&param1, &param2, &param3, &param4) != SUCCESS) WRONG_PARAM_COUNT;

zend_get_parameters_ex() проверяет только то, не пытаетесь ли вы запросить слишком много параметров. Если функция вызывается с пятью аргументами, но вы запросили в zend_get_parameters_ex() только три, вы получите не ошибку, а первые три параметра. Последующие вызовы zend_get_parameters_ex() не запросят остальные аргументы, а получать снова те же самые аргументы.

Математика решение задач