ホームページ >バックエンド開発 >PHPチュートリアル >PHP拡張の拡張関数におけるパラメータの受け渡し例とパラメータの取得例を詳しく解説
前回の記事でphp拡張機能の拡張フレームワークを自動生成したことで、php拡張機能のフレームワークについては基本的にはある程度理解できたといえます。と重要なポイントは説明しましたが、やはり重要なのは PHP_FUNCTION の関数をどのように記述するかです。
この記事では主に、PHP が拡張機能を呼び出すときにパラメーターを渡す方法と、拡張機能が呼び出しを受け取る方法を記録します。自分のメモとして
zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, &参数1,&参数2…);最初のパラメータは、関数に渡されるパラメータの数です。通常のアプローチは、これを ZEND_NUM_ARGS() に渡すことです。 (ZEND_NUM_ARGS()で「渡されるパラメータの数だけ」を表現) これは関数に渡されるパラメータの総数を表すマクロです。 2 番目のパラメータはスレッド セーフのため、常に TSRMLS_CC マクロを渡します。 3 番目のパラメーターは、関数で予期されるパラメーターのタイプを指定する文字列で、その後にパラメーター値で更新する必要がある変数のリストが続きます。 PHP は弱い型指定言語であるため、緩い変数定義と動的な型判定を使用しますが、C 言語は強い型指定があり、zend_parse_parameters() はさまざまな型のパラメーターを期待される型に変換します。 (実際の値を期待した型に強制できない場合は警告が発行されます)4番目、5番目、n番目のパラメータはすべて渡される値の値です。 3番目のパラメータの詳細な説明 3番目のパラメータについては、選択するパラメータのリストを以下に示します:
対応するCの型 | 説明 | |
---|---|---|
long | 符号付き整数 | |
double | 浮動小数点 | |
char *, int | バイナリ文字列、length | |
zend_ bool | 論理型 (1 または ) 任意の型オブジェクトの | |
zval * | 指定されたタイプのオブジェクト。対象オブジェクトのクラス型を指定する必要があります | |
zval * | zval を何も操作せずに指定する必要があります | |
ここで特に注意が必要な点が2つあります | 1に対応するc型は2つあります。ここのパラメータは文字列型です。はい。これは、zend_parse_parameters() 関数を使用する場合、次のように使用する必要があることを示しています:zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",&name, &name_len) | 1 つは文字列の内容を表し、もう 1 つは文字列の長さを表します。 2. zval とは何ですか? |
ps: typedef については説明しません。すでに誰かが非常にうまく書いているので、typedef の使用法の概要をクリックしてください | これにも 3 つのことが含まれます。パラメーターを受信する機能を強化するには: | |
| | その前のパラメーターはすべて必要であり、その後のパラメーターは必要ありません。デフォルト値があります。 |
/
渡された変数が他の変数と zval を共有し、参照ではない場合、新しい zval の is_ref__gc==0 と refcount__gc==1.
“|”和”!”将在下文有具体例子讲解,关于”/”虽然大概懂意思,但没想到具体的例子。
正常的样子
在PHP中
<?phpfunction my_function($msg) { echo "我收到参数啦: {$msg}!\n"; } my_function('咖啡色的羊驼');
如果my_function写成PHP扩展:
ZEND_FUNCTION(my_function) { char *msg; int msg_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",&msg, &msg_len) == FAILURE){ RETURN_NULL(); } php_printf("我收到参数啦:"); PHPWRITE(msg, msg_len); php_printf("!\n"); }
两个参数的样子
在PHP中
<?phpfunction my_function($email, $msg) { echo "我收到参数啦: {$email}、 {$msg}!\n"; } my_function('123456@qq.com', '咖啡色的羊驼');
如果my_function写成PHP扩展:
ZEND_FUNCTION(my_function) { char *email; int email_len; char *msg; int msg_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",&msg, &msg_len,&email, &email_len) == FAILURE){ RETURN_NULL(); } php_printf("我收到参数啦:"); PHPWRITE(email, email_len); PHPWRITE(msg, msg_len); php_printf("!\n"); }
两个参数,其中一个可选且有默认值
<?phpfunction my_function($email, $msg = '咖啡色的羊驼') { echo "我收到参数啦: {$email}、 {$msg}!\n"; } my_function('123456@qq.com');
如果my_function写成PHP扩展:
ZEND_FUNCTION(my_function) { char *email; int email_len; char *msg = "咖啡色的羊驼"; int msg_len = sizeof("咖啡色的羊驼") - 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",&msg, &msg_len,&email, &email_len) == FAILURE){ RETURN_NULL(); } php_printf("我收到参数啦:"); PHPWRITE(email, email_len); PHPWRITE(msg, msg_len); php_printf("!\n"); }
这里说明了”|”的使用
参数为null时,省内存的写法
先来不省的写法
ZEND_FUNCTION(my_function) { zval *val; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",&val) == FAILURE) { RETURN_NULL(); } }
省内存
ZEND_FUNCTION(my_function) { zval *val; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!",&val) == FAILURE) { RETURN_NULL(); } }
这里例子用上了”!”,每个zval,包括IS_NULL型的zval,都需要占用一定的内存空间,需要cpu的计算资源来为它申请内存、初始化,并在它们完成工作后释放掉。但是很多代码都都没有意识到这一点。有很多代码都会把一个null型的值包裹成zval的IS_NULL类型,在扩展开发里这种操作是可以优化的,我们可以把参数接收成C语言里的NULL。
所以就差了一个!,第二个例子就更省了内存。
例子是最好的用法讲解,上例子:
ZEND_FUNCTION(my_function) { zval *email; if (zend_get_parameters(ZEND_NUM_ARGS(), 1, &email)== FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING,"至少需要一个参数"); RETURN_NULL(); } // ... }
1.能够兼容老版本的PHP,并且只以zval为载体来接收参数。
2.直接获取,而不做解析,不会进行类型转换,所有的参数在扩展实现中的载体都需要是zval类型的。
3.接受失败的时候,不会自己抛出错误,也不能方便的处理有默认值的参数。
4.会自动的把所有符合copy-on-write的zval进行强制分离,生成一个崭新的copy送到函数内部。
综合评价:还是用zend_parse_parameters吧,这个函数了解下即可,不给力。
ZEND_FUNCTION(my_function) { zval **msg; if (zend_get_parameters_ex(1, &msg) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING,"至少需要一个参数"); RETURN_NULL(); } // ...}
不需要ZEND_NUM_ARGS()作为参数,因为它是在是在后期加入的,那个参数已经不再需要了。
1.此函数基本同zend_get_parameters()。
2.唯一不同的是它不会自动的把所有符合copy-on-write的zval进行强制分离,会用到老的zval的特性
综合评价:极端情况下可能会用到,这个函数了解下即可。
这个包括:zend_get_parameters_array_ex()和zend_get_parameters_array()
ZEND_FUNCTION(var_dump) { int i, argc = ZEND_NUM_ARGS(); zval ***args; args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); if (ZEND_NUM_ARGS() == 0 || zend_get_parameters_array_ex(argc, args) == FAILURE) { efree(args); WRONG_PARAM_COUNT; } for (i=0; i<argc; i++) { php_var_dump(args[i], 1 TSRMLS_CC); } efree(args); }
这个有点复杂,需要解释一下:
程序首先获取参数数量,然后通过safe_emalloc函数申请了相应大小的内存来存放这些zval**类型的参数。这里使用了zend_get_parameters_array_ex()函数来把传递给函数的参数填充到args中。
是的
这个参数专门用于解决像php里面的var_dump的一样,可以无限传参数进去的函数的实现
1.用于应对无限参数的扩展函数的实现。
2.zend_get_parameters_array与zend_get_parameters_array_ex唯一不同的是它将zval*类型的参数填充到args中,并且需要ZEND_NUM_ARGS()作为参数。
综合评价:当遇到确实需要处理无限参数的时候,真的要用这个函数了。zend_parse_parameters真的做不到啊~
抛开一切,最少也要学会zend_parse_parameters()的用法。好的。扩展函数传参数的技能get了。
以上がPHP拡張の拡張関数におけるパラメータの受け渡し例とパラメータの取得例を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。