<pre id="bbfd9"><del id="bbfd9"><dfn id="bbfd9"></dfn></del></pre>

          <ruby id="bbfd9"></ruby><p id="bbfd9"><mark id="bbfd9"></mark></p>

          <p id="bbfd9"></p>

          <p id="bbfd9"><cite id="bbfd9"></cite></p>

            <th id="bbfd9"><form id="bbfd9"><dl id="bbfd9"></dl></form></th>

            <p id="bbfd9"><cite id="bbfd9"></cite></p><p id="bbfd9"></p>
            <p id="bbfd9"><cite id="bbfd9"><progress id="bbfd9"></progress></cite></p>
            php語言

            php內核分析之擴展

            時間:2025-01-31 11:06:42 php語言 我要投稿
            • 相關推薦

            php內核分析之擴展

              以下是百分網小編精心為大家整理的關于php內核擴展方面的分析,歡迎閱讀參考!更多內容請關注應屆畢業生網!

              這里閱讀的php版本為PHP-7.1.0 RC3,閱讀代碼的平臺為linux。

              我們研究下反射這個擴展。

              反射這個擴展目錄是存在在:ext/reflection。其實里面的代碼很簡單。一個.h文件,一個 .c文件。

              我們先看下.c文件中,會看到很多ZEND_METHOD

              ZEND_METHOD(reflection_function, getReturnType)

              {

              ...

              }

              對應的宏:

              #define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_MN(classname##_##name))

              #define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)

              #define ZEND_MN(name) zim_##name

              #define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value

              這里的##代表的是連接,展開實際上就是:

              void zim_reflection_function_getReturnType(zend_execute_data *execute_data, zval *return_value)

              總而言之,我們這里是使用ZEND_METHOD定義了一個函數zim_reflection_function_getReturnType,那從執行代碼是怎么調用到這里的呢?

              好吧,所以我們這里是看不到擴展的調用堆棧的。那我們用gdb看下調用堆棧。

              寫個使用反射擴展的腳本:

              1

              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());

              使用gdb進行打點,我們看了下getReturnType的擴展定義,里面有個在擴展代碼中的函數reflection_type_factory,就使用這個打點了。

              (gdb) b reflection_type_factory

              (gdb) run -f /home/xiaoju/software/php7/demo/echo.php

              (gdb) s

              (gdb) bt

              #0 reflection_type_factory (fptr=0x7ffff6004210, closure_object=0x0, arg_info=0x7ffff6079048,

              object=0x7ffff60140d0) at /home/xiaoju/webroot/php-src/php-src-master/ext/reflection/php_reflection.c:1280

              #1 0x0000000000760d23 in ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER (execute_data=0x7ffff6014030)

              at /home/xiaoju/webroot/php-src/php-src-master/Zend/zend_vm_execute.h:1097

              #2 0x000000000073fc88 in execute_ex (ex=)

              at /home/xiaoju/webroot/php-src/php-src-master/Zend/zend_vm_execute.h:432

              #3 0x000000000078b670 in zend_execute (op_array=0x7ffff60782a0, return_value=)

              at /home/xiaoju/webroot/php-src/php-src-master/Zend/zend_vm_execute.h:474

              #4 0x00000000006e48a3 in zend_execute_scripts (type=8, retval=0x0, file_count=3)

              at /home/xiaoju/webroot/php-src/php-src-master/Zend/zend.c:1464

              #5 0x0000000000684870 in php_execute_script (primary_file=0x7fffffffe090)

              at /home/xiaoju/webroot/php-src/php-src-master/main/main.c:2541

              #6 0x000000000078e9ea in do_cli (argc=3, argv=0xee1bc0)

              at /home/xiaoju/webroot/php-src/php-src-master/sapi/cli/php_cli.c:994

              #7 0x000000000078f1ea in main (argc=3, argv=0xee1bc0)

              at /home/xiaoju/webroot/php-src/php-src-master/sapi/cli/php_cli.c:1387

              (gdb)

              好了,很清晰可以看到這個脈絡:

              main->do_cli->php_execute_scripts->zend_execute->execute_ex->ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER->reflection_type_factory

              對于main, do_cli, php_execute_scripts, zend_execute, execute_ex 根據前面的main函數分析,我們很容易能夠理解各個函數的作用。換句話說,execute_ex才是實際上調用opcode最終最重要的函數。

              對照這個腳本的opcode:

              L1-21 {main}() /home/xiaoju/software/php7/demo/echo.php - 0x7fd6a127f000 + 30 ops

              L3 #0 NOP

              L11 #1 NOP

              L16 #2 NEW "ReflectionMethod" @1

              L16 #3 SEND_VAL_EX "B" 1

              L16 #4 SEND_VAL_EX "test" 2

              L16 #5 DO_FCALL

              L16 #6 ASSIGN $rc @1

              L17 #7 INIT_FCALL 112 "var_dump"

              L17 #8 INIT_METHOD_CALL $rc "getReturnType"

              L17 #9 DO_FCALL @4

              L17 #10 CAST @4 ~5

              L17 #11 SEND_VAL ~5 1

              L17 #12 INIT_METHOD_CALL $rc "getReturnType"

              L17 #13 DO_FCALL @6

              L17 #14 SEND_VAR @6 2

              L17 #15 DO_ICALL

              L19 #16 NEW "ReflectionFunction" @8

              L19 #17 SEND_VAL_EX "getB" 1

              L19 #18 DO_FCALL

              L19 #19 ASSIGN $rc @8

              L20 #20 INIT_FCALL 112 "var_dump"

              L20 #21 INIT_METHOD_CALL $rc "getReturnType"

              L20 #22 DO_FCALL @11

              L20 #23 CAST @11 ~12

              L20 #24 SEND_VAL ~12 1

              L20 #25 INIT_METHOD_CALL $rc "getReturnType"

              L20 #26 DO_FCALL @13

              L20 #27 SEND_VAR @13 2

              L20 #28 DO_ICALL

              L21 #29 RETURN 1

              可以看到這個$rc->getReturnType()相對應的opcode是在#9 DO_FCALL

              好了,我們從execute_ex開始跟,可以簡化成:

              // 最核心的執行opcode的函數

              ZEND_API void execute_ex(zend_execute_data *ex)

              {

              ...

              while (1) {

              int ret;

              if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0)) {

              ...

              }

              }

              ...

              }

              這里的handler每個opcode的op對應一個handler,比如 DO_FCALL對應的handler就是ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER(和剛才的bt現顯示的堆棧一樣)

              簡化下偽代碼如下:

              // DO_FCALL這個opcode對應的處理函數

              static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)

              {

              ...

              if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { // 如果是用戶定義的函數

              ...

              zend_execute_ex(call);

              ...

              } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { // 如果是內部函數

              ...

              if (!zend_execute_internal) {

              fbc->internal_function.handler(call, ret); // 執行這個internal_function所定義的handler函數,這個就是實際的調用方法了,命名為:zim_[class]_function_[function]

              } else {

              zend_execute_internal(call, ret);

              }

              ...

              } else { /* ZEND_OVERLOADED_FUNCTION */

              ...

              if (UNEXPECTED(!zend_do_fcall_overloaded(fbc, call, ret))) {

              HANDLE_EXCEPTION();

              }

              ...

              }

              fcall_end:

              ...

              ZEND_VM_SET_OPCODE(opline + 1);

              ZEND_VM_CONTINUE(); // 下一條op

              }

              可以看到,這個函數里面就有一個fbc->internal_function.handler,這里的internal_function對應的函數名就是zim_reflection_function_getReturnType,和我們擴展模塊里面定義的函數對應上了。可以說,這里就進入了擴展里面了。

            【php內核分析之擴展】相關文章:

            php內核分析之zval09-07

            php內核分析之opcode08-04

            php內核分析之全局變量09-03

            php內核分析之zend-compile09-01

            php內核分析之do-cli05-30

            php內核分析之sapi-module-struct10-17

            php內核分析之ZTS和zend-try07-18

            PHP擴展程序講解11-10

            PHP PDO的擴展內容06-21

                    <pre id="bbfd9"><del id="bbfd9"><dfn id="bbfd9"></dfn></del></pre>

                    <ruby id="bbfd9"></ruby><p id="bbfd9"><mark id="bbfd9"></mark></p>

                    <p id="bbfd9"></p>

                    <p id="bbfd9"><cite id="bbfd9"></cite></p>

                      <th id="bbfd9"><form id="bbfd9"><dl id="bbfd9"></dl></form></th>

                      <p id="bbfd9"><cite id="bbfd9"></cite></p><p id="bbfd9"></p>
                      <p id="bbfd9"><cite id="bbfd9"><progress id="bbfd9"></progress></cite></p>
                      飘沙影院