PHP7內部函數的參數是如何解析的

由於使用yaf框架Yaf_Response_Http::getHeader沒有相關的文檔只能查看源碼確認。通過源碼可以看出有一個可選參數。

PHP內核函數使用zend_parse_parameters()將實際參數的值接收到C變量中。
此函數使用scanf()方法進行參數定義。
由包含說明符列表的字符串定義的所需數據的數量和類型(“s” - 表示字符串,“l”表示長整數等)。
不幸的是,每次php調用此函數時都必須解析此字符串,這會產生顯着的性能開銷。
在php7之後的版對此優化,使用新API fast_zpp宏 提高性能。

在php7可以使用zend_parse_parameters、fast_zpp兩種方式獲取php參數,以下是內部函數獲取參數源碼。

/** {{{ proto public Yaf_Response_Http::getHeader(void)
*/
PHP_METHOD(yaf_response_http, getHeader) {

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &name) == FAILURE) {
		return;
	}
ZEND_FUNCTION(define)
{

	ZEND_PARSE_PARAMETERS_START(2, 3)
		Z_PARAM_STR(name)
		Z_PARAM_ZVAL(val)
		Z_PARAM_OPTIONAL
		Z_PARAM_BOOL(non_cs)
	ZEND_PARSE_PARAMETERS_END();

第一個代碼片斷取自鳥哥yaf框架源碼
https://github.com/laruence/yaf/blob/931dc56c7a53c388c21d679ae10dfe0b245aed32/responses/yaf_response_http.c
第二個代碼片斷取處php7.4 defin函數源碼
https://github.com/php/php-src/blob/master/Zend/zend_builtin_functions.c

使用舊API獲取參數

zend_parse_parameters()

這包括了兩個操作: ⼀個是取參數的個數, ⼀個是解析參數列表。
取參數的個數

取參數的個數是通過ZEND_NUM_ARGS()宏來實現的。 其定義如下:

#define ZEND_NUM_ARGS() (ht)

解析參數列表
源碼可在zend_API.h查看

PHP內部函數在解析參數時使⽤的是 zend_parse_parameters。 它可以⼤⼤簡化參數的接收處理⼯作, 雖然它在處理可變參數時還有點弱。
其聲明如下:

ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...)
  • 第⼀個參數num_args表明表示想要接收的參數個數, 我們經常使⽤ZEND_NUM_ARGS() 來表示對傳⼊的參數“有多少要多少”。
  • 第⼆參數應該總是宏 TSRMLS_CC 。
  • 第三個參數 type_spec 是⼀個字符串, ⽤來指定我們所期待接收的各個參數的類型, 有點類似於printf 中指定輸出格式的那個格式化字串。
  • 剩下的參數就是我們⽤來接收PHP參數值的變量的指針。

zend_parse_parameters() 在解析參數的同時會盡可能地轉換參數類型, 這樣就可以確保我們總是能得到所期望的類型的變量。 任何⼀種標量類型都可以轉換爲另外⼀種標量類型, 但是不能在標量類型與複雜類型(⽐如數組、 對象和資源等) 之間進⾏轉換。 如果成功地解析和接收到了參數並且在轉換期間也沒出現錯誤, 那麼這個函數就會返回 SUCCESS, 否則返回 FAILURE。 如果這個函數不能接收到所預期的參數個數或者不能成功轉換參數類型時就會拋出⼀些錯誤信息。
第三個參數指定的各個參數類型列表如下所示:

  • l - ⻓整形
  • d - 雙精度浮點類型
  • s - 字符串 (也可能是空字節)和其⻓度
  • b - 布爾型
  • r - 資源, 保存在 zval*
  • a - 數組, 保存在 zval*
  • o - (任何類的) 對象, 保存在 zval *
  • O - (由class entry 指定的類的) 對象, 保存在 zval *
  • z - 實際的 zval*
    除了各個參數類型, 第三個參數還可以包含下⾯⼀些字符, 它們的含義如下:
  • | - 表明剩下的參數都是可選參數。 如果⽤戶沒有傳進來這些參數值, 那麼這些值就會被初始化成默認值。
  • / - 表明參數解析函數將會對剩下的參數以 SEPARATE_ZVAL_IF_NOT_REF() 的⽅式來提供這個參數的⼀份拷⻉, 除⾮這些參數是⼀個引⽤。
  • ! - 表明剩下的參數允許被設定爲 NULL(僅⽤在 a、 o、 O、 r和z身上) 。 如果⽤戶傳進來了⼀個 NULL 值, 則存儲該參數的變量將會設置爲 NULL

使用新API獲取參數

ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)

兩個參數,分別是必傳參數和最多可選參數。

Z_PARAM_STR(zend_string *dest)
Z_PARAM_STRING(char *dest, size_t *dest_len)
Z_PARAM_ZVAL(zval *dest)
Z_PARAM_LONG(zend_long dest)
Z_PARAM_ARRAY(zval *dest)
Z_PARAM_RESOURCE(zval *dest)
Z_PARAM_OPTIONAL

常用獲取參數方法

END_PARSE_PARAMETERS_END()

結束獲取參數
新API涵蓋了舊API的所有功能。
新API與舊API對照表

specifie Fast ZPP API macro args
| Z_PARAM_OPTIONAL
a Z_PARAM_ARRAY(dest) dest - zval*
A Z_PARAM_ARRAY_OR_OBJECT(dest) dest - zval*
b Z_PARAM_BOOL(dest) dest - zend_bool
C Z_PARAM_CLASS(dest) dest - zend_class_entry*
d Z_PARAM_DOUBLE(dest) dest - double
f Z_PARAM_FUNC(fci, fcc) fci - zend_fcall_info, fcc - zend_fcall_info_cache
h Z_PARAM_ARRAY_HT(dest) dest - HashTable*
H Z_PARAM_ARRAY_OR_OBJECT_HT(dest) dest - HashTable*
l Z_PARAM_LONG(dest) dest - long
L Z_PARAM_STRICT_LONG(dest) dest - long
o Z_PARAM_OBJECT(dest) dest - zval*
O Z_PARAM_OBJECT_OF_CLASS(dest, ce) dest - char*, dest_len - int
p Z_PARAM_PATH(dest, dest_len) dest - zval*
P Z_PARAM_PATH_STR(dest) dest - zend_string*
r Z_PARAM_RESOURCE(dest) dest - zval*
s Z_PARAM_STRING(dest, dest_len) dest - char*, dest_len - int
S Z_PARAM_STR(dest) dest - zend_string*
z Z_PARAM_ZVAL(dest) dest - zval*
Z_PARAM_ZVAL_DEREF(dest) dest - zval*
+ Z_PARAM_VARIADIC(’+’, dest, num) dest - zval*, num int
* Z_PARAM_VARIADIC(’*’, dest, num) dest - zval*, num int
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章