関数を呼び出すには、関数の名前、パラメーター、関数の定義 (つまり、関数の具体的な実行内容) など、いくつかの基本情報が必要です。関数が定義されていれば、この関数の名前は何なのか、呼び出し時にどのようなパラメータが渡されるのか、関数の動作内容は当然わかります。ただし、Zend エンジンは私たちと違って PHP ソース コードを「理解」することができません。コードを実行する前に処理する必要があります。次の 2 つの小さな例から始めましょう:
<?php function foo(){ echo "I'm foo!"; } foo(); ?>
以下、対応する OPCODES を見てみましょう:
関数名: (null) line # * OP FETCH EXT 結果
オペランド
------ -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------------- ---------------------------- ------------------------------------------- do_fcall fetch ext Returnオペランド
----------------------------------------------- ------------------------------ gt;次のセクションで詳しく説明するように、の実装は特に重要です。 ここで、関数 foo の呼び出しに注目してみましょう。 foo を呼び出すときの OPCODE は「DO_FCALL」です。DO_FCALL が関数呼び出し操作を実行すると、ZE は function_table 内の関数名に従って検索します (前述したように、ここでの関数名は str_to lower によって処理されるため、PHP の関数名は大文字と小文字が区別されません)。 -sensitive) 関数の定義が存在しない場合は、「未定義の関数 xxx() への呼び出し」というエラー メッセージが報告され、関数の zend_function 構造体ポインタが返されます。 function.type の関数は、関数が内部関数であるかどうかを判断するために使用されます。関数
関数の実行
注意深い読者は、関数が呼び出されるとき、および上記のオペコードの関数定義に「関数名:」があることに気づくかもしれませんが、実際には、ユーザー定義関数
の実行は関係ありません。他のステートメントの実行との違いは、本質的には、関数内の PHP ステートメントが関数の外部の PHP ステートメントと変わらないことです。関数本体自体の最大の違いは、その実行環境にあります。 この「実行環境」の最も重要な機能は、変数のスコープです。ご存知のとおり、関数内で定義された変数を関数の外で直接使用することはできず、その逆も同様です。そして、関数を実行する際には、関数に入る前の環境情報を保存する必要があります。関数の実行後、これらの環境情報も復元され、プログラム全体が実行を継続できるようになります。
内部函数的执行与用户函数不同。用户函数是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函数为例。在<<第一节 函数的内部结构>>中, 我们知道内部函数所在的结构体中 有一个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的定义。
以上がPHPカスタム関数の呼び出しと実行処理の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。