接收參數(shù)

? ? 寫php擴展不僅僅只是要求會c語言,還需要了解php源碼。 因為自己寫的東西,總會有這樣那樣的缺點,比如內(nèi)存泄露,不利維護(hù),開發(fā)量大等。php已經(jīng)準(zhǔn)備好了大量的宏,用于擴展開發(fā),我們遵循php提供的宏,最高效的開發(fā)擴展。

首先接收參數(shù)

1.zend_parse_params();

? ? 第一個參數(shù)表示接收參數(shù)的個數(shù),一般用宏:ZEND_NUM_ARGS() TSRMLS_CC,中間是空格,后面的是跟線程安全有關(guān)的,具體的話還不清楚,書上也沒有解釋。

? ? 第二個參數(shù)是接收參數(shù)的類型。

b ? Boolean

l ? Integer

d ? Floating point

s ? String

r ? Resource

a ? Array

o ? Object instance

O ? Object instance of a specified type ? ? ? ? ? 特定類型對象

z ? Non-specific zval ? ? ? ? ? ? ?任意類型

Z ? Dereferenced non-specific zval ? ? ? ? ?zval類型

f ? ? ? ? 表示函數(shù)方法和名稱

+ ? ? ? ? 可變參類型(書上沒有,自己看var_dump源碼,做實驗得出,下面有解釋)

還有見過別的,想不起來了,以后遇到再補充了,書上只寫這么多

后面的參數(shù),就是接收的參數(shù)地址了,類似printf。

例子:

PHP_FUNCTION(sample_getlong)

{

? long foo;

? char *name;

? int name_len;

? if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"ls", &foo.&name,&name_len) == FAILURE) {

? ? ? ? RETURN_NULL();

? ?}

? ?php_printf("The integer value of the parameter you passed is: %ld\n", foo);

? ?PHPWRITE(name, name_len);

? ?RETURN_TRUE;

}

字符串會特殊一點,先是字符地址,然后是字符串長度

修飾符

? ? |? 接下來是可選參數(shù)了. 當(dāng)指定它時, 所有之前的參數(shù)都被認(rèn)為是必須的, 所有后續(xù)的參數(shù)都被認(rèn)為是可選的.

? ? !? !之前的一個修飾符對應(yīng)的參數(shù)如果是NULL, 提供的內(nèi)部變量將被設(shè)置為真實的NULL指針.

/? ? ? ? /之前的一個修飾符對應(yīng)的參數(shù)指定為寫時拷貝, 它將自動的隔離到新的zval(is_ref = 0, refcount = 1)


實現(xiàn)可變參數(shù),就在參數(shù)類型字符后面加上修飾符即可,要做好初始化。

char *name;

int name_len;

char *greeting = "Mr./Mrs.";

int greeting_len = sizeof("Mr./Mrs.") - 1;

/* 如果調(diào)用時沒有傳遞第二個參數(shù), 則greeting和greeting_len保持不變. */

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",

&name, &name_len, &greeting, &greeting_len) == FAILURE) {

RETURN_NULL();

}

php_printf("Hello ");

PHPWRITE(greeting, greeting_len);

php_printf(" ");

PHPWRITE(name, name_len);

php_printf("!\n");


當(dāng)一個變量傳遞給別的函數(shù)時候,不論是否被引用傳值,refcount至少是2,一個是自己,一個是函數(shù)的copy(但不是真正的copy),所以,如果要對變量進(jìn)行修改,要進(jìn)行隔離拷貝。所以要使用 / 修飾符.

還有一組別的宏用來接收參數(shù)(老版本的,十分不友好,還是不提了)

可以看standard/var.c ? ? 看看vardump的實現(xiàn)

PHP_FUNCTION(var_dump)

{

zval ***args;

int argc;

int i;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {

return;

}

for (i = 0; i < argc; i++) {

php_var_dump(args[i], 1 TSRMLS_CC);

}

efree(args);

}

這個類型符號"+",是可變參數(shù)類型,argc是參數(shù)個數(shù),var_dump($a,$b,$c),argc是3。然后php_var_dump分別輸出每個變量。


zend_API.c有關(guān)于接收參數(shù)的實現(xiàn)。

va_list是c語言里面接收可變參數(shù)宏

參考zend_parse_parameters的實現(xiàn):

ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, const char *type_spec, ...) /* {{{ */

{

va_list va;

int retval;

RETURN_IF_ZERO_ARGS(num_args, type_spec, 0);

va_start(va, type_spec); //初始化

retval = zend_parse_va_args(num_args, type_spec, &va, 0 TSRMLS_CC); //這里面是php做的一層封裝,里面的核心是va_arg獲取可變參數(shù)

va_end(va);//清空可變參列表

return retval;

}

INTSIZEOF 宏,獲取類型占用的空間長度,最小占用長度為int的整數(shù)倍:#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

VA_START宏,獲取可變參數(shù)列表的第一個參數(shù)的地址(ap是類型為va_list的指針,v是可變參數(shù)最左邊的參數(shù)):

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

VA_ARG宏,獲取可變參數(shù)的當(dāng)前參數(shù),返回指定類型并將指針指向下一參數(shù)(t參數(shù)描述了當(dāng)前參數(shù)的類型):

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

VA_END宏,清空va_list可變參數(shù)列表:

#define va_end(ap) ( ap = (va_list)0 )

如果有多個可變參,那么就循環(huán)va_arg。



在強調(diào)一次,接收參數(shù)時候,如果參數(shù)要修改,需要寫時復(fù)制,那么需要"/"修飾符。(原因在zend內(nèi)存管理有解釋)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容