Maison  >  Article  >  développement back-end  >  Explication détaillée d'exemples de passage de paramètres et d'obtention de paramètres dans la fonction d'extension de l'extension PHP

Explication détaillée d'exemples de passage de paramètres et d'obtention de paramètres dans la fonction d'extension de l'extension PHP

黄舟
黄舟original
2017-08-14 09:37:492030parcourir

Avant-propos

Après la génération automatique du framework d'extension de l'extension PHP dans l'article précédent, j'ai une compréhension globale du framework d'extension PHP. En gros, on peut dire que j'ai une certaine compréhension. de la façon d'écrire des extensions PHP et les points clés Mais la clé réside dans la façon d'écrire la fonction PHP_FUNCTION.
Cet article enregistre principalement comment PHP transmet les paramètres lors de l'appel d'une extension et comment la fonction d'extension reçoit l'appel. Traitez-le comme votre propre mémo

Texte

1.zend_parse_parameters

Pour obtenir les paramètres transmis par la fonction, vous pouvez utiliser la fonction zend_parse_parameters. Les étudiants attentifs constateront que le. La fonction par défaut générée par le fonctionnaire est également Utilisez cette fonction pour recevoir les paramètres.

Comment utiliser cette fonction ?

Tout d'abord, vous pouvez utiliser ce livre en lisant comme le scanf de PHP. (Si vous n'êtes pas familier avec cette fonction, n'hésitez pas à lire ici)

zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, &参数1,&参数2…);

Le premier paramètre est le nombre de paramètres passés à la fonction. L'approche habituelle consiste à lui transmettre ZEND_NUM_ARGS(). (ZEND_NUM_ARGS() pour exprimer "autant qu'il y a de paramètres" transmis) Il s'agit d'une macro qui représente le nombre total de paramètres passés à la fonction.

Le deuxième paramètre concerne la sécurité des threads, transmettez toujours la macro TSRMLS_CC.

Le troisième paramètre est une chaîne qui spécifie le type de paramètre attendu par la fonction, suivi d'une liste de variables qui doivent être mises à jour avec la valeur du paramètre. Puisque PHP est un langage faiblement typé, il utilise des définitions de variables lâches et un jugement de type dynamique, tandis que le langage C est fortement typé, et zend_parse_parameters() sert à convertir différents types de paramètres dans le type attendu. (Lorsque la valeur réelle ne peut pas être forcée dans le type attendu, un avertissement sera émis)

Les quatrième, cinquième et nième paramètres sont toutes les valeurs des valeurs à transmettre.

Explication détaillée du troisième paramètre

Concernant le troisième paramètre, voici une liste de paramètres parmi lesquels choisir :

类型指定符 对应的C类型 描述
l long 符号整数
d double 浮点数
s char *, int 二进制字符串,长度
b zend_bool 逻辑型(1或0)
r zval * 资源(文件指针,数据库连接等)
a zval * 联合数组
o zval * 任何类型的对象
O zval * 指定类型的对象。需要提供目标对象的类类型
z zval * 无任何操作的zval

Il y a deux points qui nécessitent une attention particulière ici
1. Le type c correspondant au type chaîne a ici deux paramètres. Oui. Cela montre que lorsque vous utilisez la fonction zend_parse_parameters(), vous devez l'utiliser comme ceci :

zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",&name, &name_len)

L'un représente le contenu de la chaîne et l'autre est la longueur de la chaîne.

2. J'ai besoin de savoir brièvement, qu'est-ce que zval ?
zval est le conteneur de valeurs du moteur Zend. Que la variable soit un booléen, une chaîne ou tout autre type, ses informations sont toujours contenues dans une union zval. Jetons un coup d'œil à la structure de zval :

typedef union _zval {    long lval;    double dval;    struct {        char *val;        int len;

    } str;

    HashTable *ht;

    zend_object_value obj;

} zval;

ps : je n'expliquerai pas typedef car j'ai trouvé que quelqu'un l'avait déjà très bien écrit. Veuillez cliquer ici pour un résumé de l'utilisation de typedef<.>

Le bord implique également trois utilisations supplémentaires pour améliorer notre capacité à recevoir des paramètres :

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

走一波与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了。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn