內容均以php5.6.14爲例.php
從一個封裝 uniqid 的例子來說。html
/* {{{ wrapper of uniqid */ PHP_FUNCTION(fox) {
// #1. zval *prefix, *more = NULL; zval function, *params[2] = {0}; // #2. if ( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &prefix, &more) == FAILURE ) { RETURN_FALSE; } params[0] = prefix; if (more) { params[1] = more; } // #3. ZVAL_STRING(&function, "uniqid", 0);
// #4. if ( call_user_function(EG(function_table), NULL, &function, return_value, ZEND_NUM_ARGS(), params TSRMLS_CC) == FAILURE ) { if (return_value) { zval_dtor(return_value); } zend_error(E_WARNING, "%s() calling %s() failed.", get_active_function_name(TSRMLS_C), Z_STRVAL(function)); RETURN_FALSE; } RETURN_STRING(Z_STRVAL_P(return_value), 0); } /* }}} */
#1.git
zval 不賦值默認是非空,不要隨意給 聲明的 zval 賦值爲 NULL,除非你知道本身在幹什麼,比方用在判斷是否有傳參;github
若是你想對可選的參數使用默認值 farwish,能夠像下面這樣 (非用於上例):app
if (more == NULL) { MAKE_STD_ZVAL(more); Z_STRVAL_P(more) = "farwish"; Z_STRLEN_P(more) = strlen("farwish"); Z_TYPE_P(more) = IS_STRING; } params[1] = more;
還有別忘了 call_user_function 中的參數個數就不能再用 ZEND_NUM_ARGS(),寫固定值 2 就能夠了。測試
#2.ui
接收的參數類型必須用雙引號包裹,爲了不其它地方也遇到這種錯誤,最好後面統一都用雙引號。spa
若是接收的參數含 char *name 類型的, 別忘了要有 uint *len 跟在它後面傳入。指針
#3. #4.code
若是開頭聲明的是 zval *function, 而且 ZVAL_STRING 賦值 和 call_user_function 的調用都傳 function, 編譯能經過, 可是使用會segmentaion fault;測試證實, ZVAL_STRING 第一個參數必定是指向 zval 的地址, 而不是簡單的傳 zval *, 由於宏中作了 zval *__z = (z) 這麼一件事, 若是 z 已是指針, 那麼值就不對了.
./Zend/zend_execute_API.c:575
int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC)
zval function_name, retval_ptr;
Thats all.