Zusammenfassung: Die hier gelesene PHP-Version ist PHP-7.1.0 RC3 und die Plattform zum Lesen des Codes ist Linux. Lassen Sie uns diese Erweiterung der Reflexion untersuchen. Das Reflection-Erweiterungsverzeichnis befindet sich unter: ext/reflection. Tatsächlich ist der darin enthaltene Code sehr einfach. Eine .h-Datei und eine .c-Datei. Werfen wir zunächst einen Blick auf die .c-Datei und wir werden viel sehen ...
Die hier gelesene PHP-Version ist PHP-7.1.0 RC3, und die Plattform zum Lesen des Codes ist Linux.
Lassen Sie uns die Reflexionserweiterung untersuchen.
Das Reflection-Erweiterungsverzeichnis existiert in: ext/reflection. Tatsächlich ist der darin enthaltene Code sehr einfach. Eine .h-Datei und eine .c-Datei.
Werfen wir zunächst einen Blick auf die .c-Datei. Wir werden viele Makros sehen, die ZEND_METHOD entsprechen
1 ZEND_METHOD(reflection_function, getReturnType) 2 { 3 ... 4 }
:
1 #define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_MN(classname##_##name)) 2 #define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS) 3 #define ZEND_MN(name) zim_##name 4 #define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value
Das ## hier stellt die Verbindung dar. Die Erweiterung lautet tatsächlich:
void zim_reflection_function_getReturnType(zend_execute_data *execute_data, zval *return_value)
Kurz gesagt, wir verwenden ZEND_METHOD, um eine Funktion zim_reflection_function_getReturnType zu definieren. Wie wird sie hier aus dem Ausführungscode aufgerufen?
Okay, wir können den erweiterten Aufrufstapel hier nicht sehen. Dann schauen wir uns mit gdb den Aufrufstapel an.
Schreiben Sie ein Skript mit Reflection-Erweiterung:
1 <?php 2 3 class B 4 { 5 public function test(): B 6 { 7 8 } 9 } 10 11 function getB(): B 12 { 13 14 } 15 16 $rc = new ReflectionMethod('B', 'test'); 17 var_dump((string)$rc->getReturnType(), $rc->getReturnType()); 18 19 $rc = new ReflectionFunction('getB'); 20 var_dump((string)$rc->getReturnType(), $rc->getReturnType());
Verwenden Sie gdb für die Verwaltung. Wir haben uns die Erweiterungsdefinition von getReturnType angesehen und es gibt eine im Erweiterungscode Für die Verwaltung wird die Funktion „reflection_type_factory“ verwendet.
01 (gdb) b reflection_type_factory 02 03 (gdb) run -f /home/xiaoju/software/php7/demo/echo.php 04 05 (gdb) s 06 07 (gdb) bt 08 #0 reflection_type_factory (fptr=0x7ffff6004210, closure_object=0x0, arg_info=0x7ffff6079048, 09 object=0x7ffff60140d0) at /home/xiaoju/webroot/php-src/php-src-master/ext/reflection/php_reflection.c:1280 10 #1 0x0000000000760d23 in ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER (execute_data=0x7ffff6014030) 11 at /home/xiaoju/webroot/php-src/php-src-master/Zend/zend_vm_execute.h:1097 12 #2 0x000000000073fc88 in execute_ex (ex=<value optimized="" out="">) 13 at /home/xiaoju/webroot/php-src/php-src-master/Zend/zend_vm_execute.h:432 14 #3 0x000000000078b670 in zend_execute (op_array=0x7ffff60782a0, return_value=<value optimized="" out="">) 15 at /home/xiaoju/webroot/php-src/php-src-master/Zend/zend_vm_execute.h:474 16 #4 0x00000000006e48a3 in zend_execute_scripts (type=8, retval=0x0, file_count=3) 17 at /home/xiaoju/webroot/php-src/php-src-master/Zend/zend.c:1464 18 #5 0x0000000000684870 in php_execute_script (primary_file=0x7fffffffe090) 19 at /home/xiaoju/webroot/php-src/php-src-master/main/main.c:2541 20 #6 0x000000000078e9ea in do_cli (argc=3, argv=0xee1bc0) 21 at /home/xiaoju/webroot/php-src/php-src-master/sapi/cli/php_cli.c:994 22 #7 0x000000000078f1ea in main (argc=3, argv=0xee1bc0) 23 at /home/xiaoju/webroot/php-src/php-src-master/sapi/cli/php_cli.c:1387 24 (gdb)</value></value>
Okay, Sie können diesen Kontext sehr deutlich sehen:
main->do_cli->php_execute_scripts->zend_execute->execute_ex->ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER->reflection_type_factory
Für main, do_cli, php_execute_scripts, zend_execute,execute_ex können wir gemäß der vorherigen Hauptfunktionsanalyse leicht verstehen die Rolle jeder Funktion. Mit anderen Worten,execute_ex ist die wichtigste Funktion, die tatsächlich Opcode aufruft.
Vergleichen Sie den Opcode dieses Skripts:
01 L1-21 {main}() /home/xiaoju/software/php7/demo/echo.php - 0x7fd6a127f000 + 30 ops 02 L3 #0 NOP 03 L11 #1 NOP 04 L16 #2 NEW "ReflectionMethod" @1 05 L16 #3 SEND_VAL_EX "B" 1 06 L16 #4 SEND_VAL_EX "test" 2 07 L16 #5 DO_FCALL 08 L16 #6 ASSIGN $rc @1 09 L17 #7 INIT_FCALL 112 "var_dump" 10 L17 #8 INIT_METHOD_CALL $rc "getReturnType" 11 L17 #9 DO_FCALL @4 12 L17 #10 CAST @4 ~5 13 L17 #11 SEND_VAL ~5 1 14 L17 #12 INIT_METHOD_CALL $rc "getReturnType" 15 L17 #13 DO_FCALL @6 16 L17 #14 SEND_VAR @6 2 17 L17 #15 DO_ICALL 18 L19 #16 NEW "ReflectionFunction" @8 19 L19 #17 SEND_VAL_EX "getB" 1 20 L19 #18 DO_FCALL 21 L19 #19 ASSIGN $rc @8 22 L20 #20 INIT_FCALL 112 "var_dump" 23 L20 #21 INIT_METHOD_CALL $rc "getReturnType" 24 L20 #22 DO_FCALL @11 25 L20 #23 CAST @11 ~12 26 L20 #24 SEND_VAL ~12 1 27 L20 #25 INIT_METHOD_CALL $rc "getReturnType" 28 L20 #26 DO_FCALL @13 29 L20 #27 SEND_VAR @13 2 30 L20 #28 DO_ICALL 31 L21 #29 RETURN 1
Sie können sehen, dass der Opcode, der $rc->getReturnType() entspricht, #9 DO_FCALL ist
Okay, beginnen wir mitexecute_ex, was vereinfacht werden kann zu:
01 // 最核心的执行opcode的函数 02 ZEND_API void execute_ex(zend_execute_data *ex) 03 { 04 ... 05 while (1) { 06 int ret; 07 if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0)) { 08 ... 09 } 10 11 } 12 ... 13 }
Der Handler hier entspricht einem Handler für jeden Opcode-Op, wie z. B. DO_FCALL . Der Handler ist ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER (derselbe wie der gerade von bt angezeigte Stapel)
Der vereinfachte Pseudocode lautet wie folgt:
01 // DO_FCALL这个opcode对应的处理函数 02 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) 03 { 04 ... 05 if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { // 如果是用户定义的函数 06 ... 07 zend_execute_ex(call); 08 ... 09 } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { // 如果是内部函数 10 ... 11 if (!zend_execute_internal) { 12 fbc->internal_function.handler(call, ret); // 执行这个internal_function所定义的handler函数,这个就是实际的调用方法了,命名为:zim_[class]_function_[function] 13 } else { 14 zend_execute_internal(call, ret); 15 } 16 ... 17 18 } else { /* ZEND_OVERLOADED_FUNCTION */ 19 ... 20 if (UNEXPECTED(!zend_do_fcall_overloaded(fbc, call, ret))) { 21 HANDLE_EXCEPTION(); 22 } 23 ... 24 } 25 26 fcall_end: 27 ... 28 ZEND_VM_SET_OPCODE(opline + 1); 29 ZEND_VM_CONTINUE(); // 下一条op 30 }
As Sie können sehen, dass die Funktion einen fbc->internal_function.handler enthält. Der Funktionsname, der der internal_function entspricht, ist zim_reflection_function_getReturnType, was der in unserem Erweiterungsmodul definierten Funktion entspricht. Man kann sagen, dass wir hier in die Erweiterung eingetreten sind.
Das Obige ist der Inhalt der PHP-Kernel-Analyse (7) - Erweiterung. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!