ホームページ >バックエンド開発 >PHPチュートリアル >PHP拡張の拡張関数におけるパラメータの受け渡し例とパラメータの取得例を詳しく解説

PHP拡張の拡張関数におけるパラメータの受け渡し例とパラメータの取得例を詳しく解説

黄舟
黄舟オリジナル
2017-08-14 09:37:492129ブラウズ

はじめに

前回の記事でphp拡張機能の拡張フレームワークを自動生成したことで、php拡張機能のフレームワークについては基本的にはある程度理解できたといえます。と重要なポイントは説明しましたが、やはり重要なのは PHP_FUNCTION の関数をどのように記述するかです。
この記事では主に、PHP が拡張機能を呼び出すときにパラメーターを渡す方法と、拡張機能が呼び出しを受け取る方法を記録します。自分のメモとして

テキスト

1. zend_parse_parameters

関数によって渡されるパラメータを取得するには、zend_parse_parameters 関数を使用できます。注意してください。公式に生成されたデフォルト関数もこの関数を使用してパラメータを受け取ります。

この機能の使い方は?

まず、この本はPHPのscanfのように読んで使えます。 (この関数に詳しくない方は、こちらからお読みください)

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の型 説明 l long符号付き整数ddouble浮動小数点schar *, intバイナリ文字列、lengthbzend_ bool論理型 (1 または ) 任意の型オブジェクトの Ozval * 指定されたタイプのオブジェクト。対象オブジェクトのクラス型を指定する必要がありますzzval *zval を何も操作せずに指定する必要があります1に対応するc型は2つあります。ここのパラメータは文字列型です。はい。これは、zend_parse_parameters() 関数を使用する場合、次のように使用する必要があることを示しています: 1 つは文字列の内容を表し、もう 1 つは文字列の長さを表します。 2. zval とは何ですか? zval は Zend エンジンの値コンテナです。変数がブール型、文字列、またはその他の型であるかどうかに関係なく、その情報は常に zval 共用体に含まれます。 zval の構造を見てみましょう:
typedef union _zval {    long lval;    double dval;    struct {        char *val;        int len;

    } str;

    HashTable *ht;

    zend_object_value obj;

} zval;
!
ここで特に注意が必要な点が2つあります
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",&name, &name_len)
ps: typedef については説明しません。すでに誰かが非常にうまく書いているので、typedef の使用法の概要をクリックしてください これにも 3 つのことが含まれます。パラメーターを受信する機能を強化するには:
| その前のパラメーターはすべて必要であり、その後のパラメーターは必要ありません。デフォルト値があります。
PHP言語でnull変数を受け取った場合、IS_NULL型のzvalにカプセル化せずにC言語で直接NULLに変換します。


/

渡された変数が他の変数と zval を共有し、参照ではない場合、新しい zval の is_ref__gc==0 と refcount__gc==1.

が強制的に分離されます。

“|”和”!”将在下文有具体例子讲解,关于”/”虽然大概懂意思,但没想到具体的例子。

走一波与php的交互

正常的样子

在PHP中

<?phpfunction my_function($msg) {
    echo "我收到参数啦: {$msg}!\n";
}
my_function(&#39;咖啡色的羊驼&#39;);

如果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(&#39;123456@qq.com&#39;, &#39;咖啡色的羊驼&#39;);

如果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 = &#39;咖啡色的羊驼&#39;) {
    echo "我收到参数啦: {$email}、 {$msg}!\n";
}
my_function(&#39;123456@qq.com&#39;);

如果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。
所以就差了一个!,第二个例子就更省了内存。

2.zend_get_arguments()

用法

例子是最好的用法讲解,上例子:

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吧,这个函数了解下即可,不给力。

3.zend_get_parameters_ex()

用法

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_parameter_**

这个包括: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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。