Maison  >  Article  >  développement back-end  >  Explication détaillée du processus d'appel et d'exécution de fonctions personnalisées PHP

Explication détaillée du processus d'appel et d'exécution de fonctions personnalisées PHP

伊谢尔伦
伊谢尔伦original
2017-06-27 09:37:393929parcourir

Certaines informations de base sont requises pour qu'une fonction soit appelée, comme le nom de la fonction, les paramètres et la définition de la fonction (c'est-à-dire le contenu d'exécution spécifique de la fonction). lorsqu'une fonction est définie et que nous l'exécutons. Naturellement, vous connaissez le nom de cette fonction, quels paramètres sont passés lors de l'appel et le contenu de l'opération de la fonction. Cependant, le moteur Zend ne peut pas « comprendre » le code source PHP comme nous le faisons. Il doit traiter le code avant de pouvoir l'exécuter. Commençons par les deux petits exemples suivants :

<?php
    function foo(){
        echo "I&#39;m foo!";
    }   
    foo();
?>

Jetons un coup d'œil aux opcodes correspondants :

nom de la fonction : (null)line # * op return opérandes

----------------------------------------------- ---- --------------------------------------

                                                                                                                                                                                    DO_FCALL                    
                                                                                                                                                                                                                                                                                                                                            # * op - ------------------------------------------------- - -----------------
4 0 > ECHO 1 1 > RETOUR                                                                                                                                       >
Ce qui précède représente les opcodes avec certaines informations périphériques supprimées. Les opcodes de la partie fonction sont séparés lors de l'exécution. Ceci est particulièrement important pour l'exécution de la fonction. La partie suivante le présentera en détail. Concentrons-nous maintenant sur l'appel à la fonction foo. L'OPCODE qui appelle foo est "DO_FCALL". Lorsque DO_FCALL effectue une opération d'appel de fonction, ZE recherchera en fonction du nom de la fonction dans la table_fonction (comme mentionné ci-dessus, le nom de la fonction ici est traité par str_tolower, donc le nom de la fonction PHP n'est pas majuscule). -sensible) La définition de la fonction si elle n'existe pas, le

message d'erreur

de "Appel à une fonction non définie xxx()" sera signalé s'il existe, le pointeur de structure zend_function de la fonction ; être renvoyé, puis jugé par la valeur de function.type. Que la fonction soit une
fonction interne

ou une fonction définie par l'utilisateur, appelez zend_execute_internal (zend_internal_function.handler) ou appelez directement zend_execute pour exécuter le zend_op_array contenu dans cette fonction.


Exécution de la fonction

Les lecteurs attentifs remarqueront peut-être qu'il y a un "nom de fonction :" lorsque la fonction est appelée et dans la définition de la fonction dans les opcodes ci-dessus. En fait, l'utilisateur définit la fonction L'exécution de

n'est pas différente de l'exécution d'autres instructions. Essentiellement, les instructions PHP dans la fonction ne sont pas différentes des instructions PHP en dehors de la fonction. La plus grande différence dans le corps de la fonction lui-même réside dans son environnement d'exécution. La caractéristique la plus importante de cet « environnement d'exécution » est la portée de la

variable . Comme nous le savons tous, les variables définies dans une fonction ne peuvent pas être utilisées directement en dehors de la fonction, et vice versa. Ensuite, lorsque la fonction est exécutée, les informations d'environnement avant d'entrer dans la fonction doivent être enregistrées. Une fois la fonction exécutée, ces informations d'environnement seront également restaurées, permettant à l'ensemble du programme de continuer à s'exécuter.

内部函数的执行与用户函数不同。用户函数是php语句一条条“翻译”成op_line组成的一个op_array,而内部函数则是用C来实现的,因为执行环境也是C环境, 所以可以直接调用。如下面的例子:

<?php
    $foo = &#39;test&#39;;
    print_r($foo);
?>

生成的opcodes中,内部函数和用户函数的处理都是由DO_FCALL来进行的。而在其具体实现的zend_do_fcall_common_helper_SPEC()中, 则对是否为内部函数进行了判断,如果是内部函数,则使用一个比较长的调用

((zend_internal_function *) EX(function_state).function)->handler(opline->extended_value, EX_T(opline->result.u.var).var.ptr, EX(function_state).function->common      .return_reference?&EX_T(opline->result.u.var).var.ptr:NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);

上面这种方式的内部函数是在zend_execute_internal函数没有定义的情况下。而在而在Zend/zend.c文件的zend_startup函数中,

zend_execute_internal = NULL;

此函数确实被赋值为NULL。于是我们在if (!zend_execute_internal)判断时会成立,所以我们是执行那段很长的调用。 那么,这段很长的调用到底是什么呢?以我们常用的 count函数为例。在4a863a0d9769be17e9a49a855df6b6bb>中, 我们知道内部函数所在的结构体中 有一个handler指针指向此函数需要调用的内部定义的C函数。 这些内部函数在模块初始化时就以扩展的函数的形式加载到EG(function_table)。其调用顺序:

php_module_startup --> php_register_extensions --> zend_register_internal_module
--> zend_register_module_ex --> zend_register_functions
 
zend_register_functions(NULL, module->functions, NULL, module->type TSRMLS_CC)

在standard扩展中。module的定义为:

zend_module_entry basic_functions_module = {
    STANDARD_MODULE_HEADER_EX,
    NULL,
    standard_deps,
    "standard",                 /* extension name */
    basic_functions,            /* function list */
    ... //省略}

从上面的代码可以看出,module->functions是指向basic_functions。在basic_functions.c文件中查找basic_functions的定义。

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