Maison > Article > développement back-end > Explication détaillée du processus d'appel et d'exécution de fonctions personnalisées PHP
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'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
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
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
内部函数的执行与用户函数不同。用户函数是php语句一条条“翻译”成op_line组成的一个op_array,而内部函数则是用C来实现的,因为执行环境也是C环境, 所以可以直接调用。如下面的例子:
<?php $foo = 'test'; 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!