首頁  >  文章  >  後端開發  >  解析PHP底層內核原始碼之變數 (一)

解析PHP底層內核原始碼之變數 (一)

藏色散人
藏色散人轉載
2021-06-10 14:03:543009瀏覽

本篇文章介紹《解析PHP底層核心原始碼之變數 (一)》。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

相關文章推薦:《分析PHP底層核心原始碼之變數(二) zend_string》《分析PHP底層核心原始碼之變數(三)

對於PHP底層的研究暫且覺得最重要的元素為:變數數組記憶體管理SAPI 物件虛擬機器

PHP的變數包括了20種類型所以先從變數入手或許可以更容易的理解其他元素

PHP變數的四個基本特徵:

#1.變數命名

##變數命名上, PHP繼承了Perl的語法風格,變數以美元符號開始,後面跟著變數名稱。一個有效的變數名稱由字母或底線開頭,後面跟上任意數量的字母,數字,或底線。依照正常的正規表示式,它將被表述為:'^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$'

注意: $this 是一個特殊的變量,它不能被賦值

變數預設總是傳值賦值。那也就是說,當將一個表達式的值賦予一個變數時,整個原始表達式的值被賦值到目標變數。這意味著,例如,當一個變數的值賦予另一個變數時,改變其中一個變數的值,將不會影響到另一個變數。有關這種類型的賦值操作,以後的文章也會深度講解 主要涉及到指標和寫時拷貝

PHP 也提供了另一種方式給變數賦值:引用賦值。這意味著新的變數簡單的引用(換言之,“成為其別名” 或 “指向”)了原始變數。改動新的變數將影響到原始變量,反之亦然。使用引用賦值,簡單地將一個 & 符號加到將要賦值的變數前(來源變數) (關於變數賦值以後也會深度去探討)

PHP也支援複合變數 也叫可變變數 。也就是類似$$a的變量,它會進行兩次的解釋。這為PHP帶來了非常靈活的動態特性。一個變數的變數名可以動態的設定和使用。一個普通的變數透過宣告來設定

陣列使用可變變數

為了使用陣列的可變變數名,你需要解決一個歧義問題。就是,如果你寫$$a[1],解析器需要明白究竟你的意思是要把$a[1]當成一個變量,還是要把$$a當成變量、[1]指的是這個變量的索引。解決這個歧義問題的語法是:第一種情況使用${$a[1]},第二種情況使用${$a}[1]

類別屬性也可以透過可變屬性名來訪問。可變屬性名從產生呼叫所在的變數的存取範圍內取得。例如,如果你的表達式是這樣的:$foo->$bar,那麼運行時將會在本地變數範圍內尋找變數$bar,它的值將會做為$foo物件的屬性名稱。如果$bar是個陣列也可以使用。

可變變數名稱不能用於PHP函數和類別裡的超級全域數組變數。變數$this也是一個不能動態取名的特殊變數。

2.變數的類型

在許多靜態語言中,變數在定義時就指定了,在程式運行過程中都不允許進行變更,PHP就是這樣,屬於弱型別語言,可以隨便賦予它任何類型的值。 PHP本身的變數低層儲存結構是怎麼樣的?弱型別系統的實現的方式?而這些類型之間的是怎麼相互轉換的?這將是本文的主要剖析內容。

要想深入了解PHP底層源碼必須要下載PHP的源碼包

我在Docker環境下下載了PHP 的源碼包同時安裝了gcc gcc-c 等環境為了後續的代碼跟踪debug。

[root@2890cf458ee2 cui-php]# ls
php-7.4.15  php-7.4.15.tar.gz
[root@2890cf458ee2 cui-php]#
[root@2890cf458ee2 cui-php]# cd php-7.4.15
[root@2890cf458ee2 php-7.4.15]# ls
CODING_STANDARDS.md  Makefile.objects    UPGRADING.INTERNALS  buildconf      configure.ac  main           tests
CONTRIBUTING.md      NEWS                Zend                 buildconf.bat  docs          modules        tmp-php.ini
EXTENSIONS           README.REDIST.BINS  appveyor             config.log     ext           pear           travis
LICENSE              README.md           azure                config.nice    include       run-tests.php  win32
Makefile             TSRM                azure-pipelines.yml  config.status  libs          sapi
Makefile.fragments   UPGRADING           build                configure      libtool       scripts

這裡有必要講一下 PHP原始碼的目錄結構

Zend :Zend 引擎的實作目錄。包括詞法語法解析,OPCODE,提供語言運行環境。

TSRM :執行緒安全資源管理器。

build:放置一些和原始碼編譯相關的一些檔案。

ext  :官方擴充目錄。包括array系列,pdo系列,spl系列等函數的實作。

main :實作PHP的基本設施。其實包含主要的 PHP 巨集和定義。

pear :PHP 擴充與應用倉庫。

sapi :各種伺服器抽象層的程式碼。例如apache的mod_php,cgi,fastcgi以及fpm等等介面。

tests:PHP的測試腳本集合。

scripts:Linux 下的腳本目錄。

win32:Windows平台相關的一些實作。

PHP的變數定義在Zend目錄下的zend_types.h 檔案

我們cd 到Zend目錄下

[root@2890cf458ee2 php-7.4.15]# cd Zend/
[root@2890cf458ee2 Zend]# ll
total 22404
-rwxrwxrwx  1 root root    2803 Feb  2 14:20 LICENSE
-rwxrwxrwx  1 root root    2008 Feb  2 14:20 Makefile.frag
-rwxrwxrwx  1 root root    4607 Feb  2 14:20 README.md
-rwxrwxrwx  1 root root   14168 Feb  2 14:20 Zend.m4
-rwxrwxrwx  1 root root    7634 Feb  2 14:20 bench.php
-rwxrwxrwx  1 root root    7226 Feb  2 14:20 micro_bench.php
drwxrwxrwx 29 root root   73728 Feb  2 14:20 tests
-rwxrwxrwx  1 root root   50788 Feb  2 14:20 zend.c
-rwxrwxrwx  1 root root   13913 Feb  2 14:20 zend.h
-rwxrwxrwx  1 root root     308 Feb 22 08:45 zend.lo
-rwxrwxrwx  1 root root  255768 Feb 22 08:45 zend.o
-rwxrwxrwx  1 root root  132287 Feb  2 14:20 zend_API.c
-rwxrwxrwx  1 root root   71109 Feb  2 14:20 zend_API.h
-rwxrwxrwx  1 root root     320 Feb 22 08:45 zend_API.lo
-rwxrwxrwx  1 root root  821976 Feb 22 08:45 zend_API.o
-rwxrwxrwx  1 root root   91551 Feb  2 14:20 zend_alloc.c
-rwxrwxrwx  1 root root   19213 Feb  2 14:20 zend_alloc.h
-rwxrwxrwx  1 root root     326 Feb 22 08:45 zend_alloc.lo
-rwxrwxrwx  1 root root  523816 Feb 22 08:45 zend_alloc.o
-rwxrwxrwx  1 root root    2629 Feb  2 14:20 zend_alloc_sizes.h
-rwxrwxrwx  1 root root    6071 Feb  2 14:20 zend_arena.h
-rwxrwxrwx  1 root root   60172 Feb  2 14:20 zend_ast.c
-rwxrwxrwx  1 root root   11697 Feb  2 14:20 zend_ast.h
-rwxrwxrwx  1 root root     320 Feb 22 08:46 zend_ast.lo
-rwxrwxrwx  1 root root  545136 Feb 22 08:46 zend_ast.o
-rwxrwxrwx  1 root root    6877 Feb  2 14:20 zend_bitset.h
-rwxrwxrwx  1 root root    1626 Feb  2 14:20 zend_build.h
-rwxrwxrwx  1 root root   75458 Feb  2 14:20 zend_builtin_functions.c
-rwxrwxrwx  1 root root    1505 Feb  2 14:20 zend_builtin_functions.h
-rwxrwxrwx  1 root root     362 Feb 22 08:45 zend_builtin_functions.lo
-rwxrwxrwx  1 root root  323432 Feb 22 08:45 zend_builtin_functions.o
-rwxrwxrwx  1 root root   26952 Feb  2 14:20 zend_closures.c
-rwxrwxrwx  1 root root    2209 Feb  2 14:20 zend_closures.h
-rwxrwxrwx  1 root root     335 Feb 22 08:46 zend_closures.lo
-rwxrwxrwx  1 root root  132304 Feb 22 08:46 zend_closures.o
-rwxrwxrwx  1 root root  268218 Feb  2 14:20 zend_compile.c
-rwxrwxrwx  1 root root   43638 Feb  2 14:20 zend_compile.h
-rwxrwxrwx  1 root root     332 Feb 22 08:45 zend_compile.lo
-rwxrwxrwx  1 root root 1189024 Feb 22 08:45 zend_compile.o
-rwxrwxrwx  1 root root      32 Feb 22 08:39 zend_config.h
-rwxrwxrwx  1 root root    2612 Feb  2 14:20 zend_config.w32.h
-rwxrwxrwx  1 root root   17607 Feb  2 14:20 zend_constants.c
-rwxrwxrwx  1 root root    6302 Feb  2 14:20 zend_constants.h
-rwxrwxrwx  1 root root     338 Feb 22 08:45 zend_constants.lo
-rwxrwxrwx  1 root root   86680 Feb 22 08:45 zend_constants.o
-rwxrwxrwx  1 root root    4571 Feb  2 14:20 zend_cpuinfo.c
-rwxrwxrwx  1 root root    7225 Feb  2 14:20 zend_cpuinfo.h
-rwxrwxrwx  1 root root     332 Feb 22 08:46 zend_cpuinfo.lo
-rwxrwxrwx  1 root root   12416 Feb 22 08:46 zend_cpuinfo.o
-rwxrwxrwx  1 root root    1684 Feb  2 14:20 zend_default_classes.c
-rwxrwxrwx  1 root root     356 Feb 22 08:46 zend_default_classes.lo
-rwxrwxrwx  1 root root   34040 Feb 22 08:46 zend_default_classes.o
-rwxrwxrwx  1 root root    4083 Feb  2 14:20 zend_dtrace.c
-rwxrwxrwx  1 root root    2180 Feb  2 14:20 zend_dtrace.d
-rwxrwxrwx  1 root root    1937 Feb  2 14:20 zend_dtrace.h
-rwxrwxrwx  1 root root     329 Feb 22 08:45 zend_dtrace.lo
-rwxrwxrwx  1 root root   31808 Feb 22 08:45 zend_dtrace.o
-rwxrwxrwx  1 root root    2050 Feb  2 14:20 zend_errors.h
-rwxrwxrwx  1 root root   34809 Feb  2 14:20 zend_exceptions.c
-rwxrwxrwx  1 root root    3853 Feb  2 14:20 zend_exceptions.h
-rwxrwxrwx  1 root root     341 Feb 22 08:46 zend_exceptions.lo
-rwxrwxrwx  1 root root  331592 Feb 22 08:46 zend_exceptions.o
-rwxrwxrwx  1 root root  148148 Feb  2 14:20 zend_execute.c
-rwxrwxrwx  1 root root   16926 Feb  2 14:20 zend_execute.h
-rwxrwxrwx  1 root root     332 Feb 22 08:46 zend_execute.lo
-rwxrwxrwx  1 root root 6034440 Feb 22 08:46 zend_execute.o
-rwxrwxrwx  1 root root   47231 Feb  2 14:20 zend_execute_API.c
-rwxrwxrwx  1 root root     344 Feb 22 08:45 zend_execute_API.lo
-rwxrwxrwx  1 root root  245224 Feb 22 08:45 zend_execute_API.o
-rwxrwxrwx  1 root root   10174 Feb  2 14:20 zend_extensions.c
-rwxrwxrwx  1 root root    6070 Feb  2 14:20 zend_extensions.h
-rwxrwxrwx  1 root root     341 Feb 22 08:45 zend_extensions.lo
-rwxrwxrwx  1 root root   50720 Feb 22 08:45 zend_extensions.o
-rwxrwxrwx  1 root root    1796 Feb  2 14:20 zend_float.c
-rwxrwxrwx  1 root root   15438 Feb  2 14:20 zend_float.h
-rwxrwxrwx  1 root root     326 Feb 22 08:46 zend_float.lo
-rwxrwxrwx  1 root root   32656 Feb 22 08:46 zend_float.o
-rwxrwxrwx  1 root root   40057 Feb  2 14:20 zend_gc.c
-rwxrwxrwx  1 root root    2867 Feb  2 14:20 zend_gc.h
-rwxrwxrwx  1 root root     317 Feb 22 08:46 zend_gc.lo
-rwxrwxrwx  1 root root  142080 Feb 22 08:46 zend_gc.o
-rwxrwxrwx  1 root root   38819 Feb  2 14:20 zend_generators.c
-rwxrwxrwx  1 root root    7349 Feb  2 14:20 zend_generators.h
-rwxrwxrwx  1 root root     341 Feb 22 08:46 zend_generators.lo
-rwxrwxrwx  1 root root  213744 Feb 22 08:46 zend_generators.o
-rwxrwxrwx  1 root root    7767 Feb  2 14:20 zend_globals.h
-rwxrwxrwx  1 root root    2810 Feb  2 14:20 zend_globals_macros.h
-rwxrwxrwx  1 root root   71887 Feb  2 14:20 zend_hash.c
-rwxrwxrwx  1 root root   36430 Feb  2 14:20 zend_hash.h
-rwxrwxrwx  1 root root     323 Feb 22 08:45 zend_hash.lo
-rwxrwxrwx  1 root root  579040 Feb 22 08:45 zend_hash.o
-rwxrwxrwx  1 root root    5905 Feb  2 14:20 zend_highlight.c
-rwxrwxrwx  1 root root    2268 Feb  2 14:20 zend_highlight.h
-rwxrwxrwx  1 root root     338 Feb 22 08:45 zend_highlight.lo
-rwxrwxrwx  1 root root   54368 Feb 22 08:45 zend_highlight.o
-rwxrwxrwx  1 root root   92179 Feb  2 14:20 zend_inheritance.c
-rwxrwxrwx  1 root root    2027 Feb  2 14:20 zend_inheritance.h
-rwxrwxrwx  1 root root     344 Feb 22 08:46 zend_inheritance.lo
-rwxrwxrwx  1 root root  444648 Feb 22 08:46 zend_inheritance.o
-rwxrwxrwx  1 root root   17816 Feb  2 14:20 zend_ini.c
-rwxrwxrwx  1 root root    9823 Feb  2 14:20 zend_ini.h
-rwxrwxrwx  1 root root     320 Feb 22 08:45 zend_ini.lo
-rwxrwxrwx  1 root root  114864 Feb 22 08:45 zend_ini.o
-rwxrwxrwx  1 root root   62412 Feb  2 14:20 zend_ini_parser.c
-rwxrwxrwx  1 root root    2400 Feb  2 14:20 zend_ini_parser.h
-rwxrwxrwx  1 root root     341 Feb 22 08:45 zend_ini_parser.lo
-rwxrwxrwx  1 root root  144960 Feb 22 08:45 zend_ini_parser.o
-rwxrwxrwx  1 root root   21408 Feb  2 14:20 zend_ini_parser.output
-rwxrwxrwx  1 root root   12077 Feb  2 14:20 zend_ini_parser.y
-rwxrwxrwx  1 root root  102668 Feb  2 14:20 zend_ini_scanner.c
-rwxrwxrwx  1 root root    1873 Feb  2 14:20 zend_ini_scanner.h
-rwxrwxrwx  1 root root   17171 Feb  2 14:20 zend_ini_scanner.l
-rwxrwxrwx  1 root root     344 Feb 22 08:45 zend_ini_scanner.lo
-rwxrwxrwx  1 root root  225064 Feb 22 08:45 zend_ini_scanner.o
-rwxrwxrwx  1 root root     187 Feb  2 14:20 zend_ini_scanner_defs.h
-rwxrwxrwx  1 root root   19678 Feb  2 14:20 zend_interfaces.c
-rwxrwxrwx  1 root root    4266 Feb  2 14:20 zend_interfaces.h
-rwxrwxrwx  1 root root     341 Feb 22 08:46 zend_interfaces.lo
-rwxrwxrwx  1 root root   95608 Feb 22 08:46 zend_interfaces.o
-rwxrwxrwx  1 root root    1537 Feb  2 14:20 zend_istdiostream.h
-rwxrwxrwx  1 root root    3205 Feb  2 14:20 zend_iterators.c
-rwxrwxrwx  1 root root    3404 Feb  2 14:20 zend_iterators.h
-rwxrwxrwx  1 root root     338 Feb 22 08:46 zend_iterators.lo
-rwxrwxrwx  1 root root   36896 Feb 22 08:46 zend_iterators.o
-rwxrwxrwx  1 root root  252766 Feb  2 14:20 zend_language_parser.c
-rwxrwxrwx  1 root root    5095 Feb  2 14:20 zend_language_parser.h
-rwxrwxrwx  1 root root     356 Feb 22 08:45 zend_language_parser.lo
-rwxrwxrwx  1 root root  345328 Feb 22 08:45 zend_language_parser.o
-rwxrwxrwx  1 root root 1356436 Feb  2 14:20 zend_language_parser.output
-rwxrwxrwx  1 root root   49261 Feb  2 14:20 zend_language_parser.y
-rwxrwxrwx  1 root root  186767 Feb  2 14:20 zend_language_scanner.c
-rwxrwxrwx  1 root root    2732 Feb  2 14:20 zend_language_scanner.h
-rwxrwxrwx  1 root root   69753 Feb  2 14:20 zend_language_scanner.l
-rwxrwxrwx  1 root root     359 Feb 22 08:45 zend_language_scanner.lo
-rwxrwxrwx  1 root root  475576 Feb 22 08:45 zend_language_scanner.o
-rwxrwxrwx  1 root root     267 Feb  2 14:20 zend_language_scanner_defs.h
-rwxrwxrwx  1 root root    9245 Feb  2 14:20 zend_list.c
-rwxrwxrwx  1 root root    3470 Feb  2 14:20 zend_list.h
-rwxrwxrwx  1 root root     323 Feb 22 08:45 zend_list.lo
-rwxrwxrwx  1 root root   63872 Feb 22 08:45 zend_list.o
-rwxrwxrwx  1 root root    6837 Feb  2 14:20 zend_llist.c
-rwxrwxrwx  1 root root    3790 Feb  2 14:20 zend_llist.h
-rwxrwxrwx  1 root root     326 Feb 22 08:45 zend_llist.lo
-rwxrwxrwx  1 root root   22848 Feb 22 08:45 zend_llist.o
-rwxrwxrwx  1 root root    4298 Feb  2 14:20 zend_long.h
-rwxrwxrwx  1 root root    3165 Feb  2 14:20 zend_map_ptr.h
-rwxrwxrwx  1 root root    4790 Feb  2 14:20 zend_modules.h
-rwxrwxrwx  1 root root    7322 Feb  2 14:20 zend_multibyte.c
-rwxrwxrwx  1 root root    4862 Feb  2 14:20 zend_multibyte.h
-rwxrwxrwx  1 root root     338 Feb 22 08:45 zend_multibyte.lo
-rwxrwxrwx  1 root root   56144 Feb 22 08:45 zend_multibyte.o
-rwxrwxrwx  1 root root    9837 Feb  2 14:20 zend_multiply.h
-rwxrwxrwx  1 root root   57901 Feb  2 14:20 zend_object_handlers.c
-rwxrwxrwx  1 root root   13505 Feb  2 14:20 zend_object_handlers.h
-rwxrwxrwx  1 root root     356 Feb 22 08:46 zend_object_handlers.lo
-rwxrwxrwx  1 root root  310384 Feb 22 08:46 zend_object_handlers.o
-rwxrwxrwx  1 root root    9778 Feb  2 14:20 zend_objects.c
-rwxrwxrwx  1 root root    1807 Feb  2 14:20 zend_objects.h
-rwxrwxrwx  1 root root     332 Feb 22 08:46 zend_objects.lo
-rwxrwxrwx  1 root root   59976 Feb 22 08:46 zend_objects.o
-rwxrwxrwx  1 root root    6724 Feb  2 14:20 zend_objects_API.c
-rwxrwxrwx  1 root root    4683 Feb  2 14:20 zend_objects_API.h
-rwxrwxrwx  1 root root     344 Feb 22 08:46 zend_objects_API.lo
-rwxrwxrwx  1 root root   46120 Feb 22 08:46 zend_objects_API.o
-rwxrwxrwx  1 root root   34033 Feb  2 14:20 zend_opcode.c
-rwxrwxrwx  1 root root     329 Feb 22 08:45 zend_opcode.lo
-rwxrwxrwx  1 root root  120352 Feb 22 08:45 zend_opcode.o
-rwxrwxrwx  1 root root   83363 Feb  2 14:20 zend_operators.c
-rwxrwxrwx  1 root root   34148 Feb  2 14:20 zend_operators.h
-rwxrwxrwx  1 root root     338 Feb 22 08:45 zend_operators.lo
-rwxrwxrwx  1 root root  506096 Feb 22 08:45 zend_operators.o
-rwxrwxrwx  1 root root   20146 Feb  2 14:20 zend_portability.h
-rwxrwxrwx  1 root root    3030 Feb  2 14:20 zend_ptr_stack.c
-rwxrwxrwx  1 root root    4306 Feb  2 14:20 zend_ptr_stack.h
-rwxrwxrwx  1 root root     338 Feb 22 08:45 zend_ptr_stack.lo
-rwxrwxrwx  1 root root   13104 Feb 22 08:45 zend_ptr_stack.o
-rwxrwxrwx  1 root root    3000 Feb  2 14:20 zend_range_check.h
-rwxrwxrwx  1 root root   13032 Feb  2 14:20 zend_signal.c
-rwxrwxrwx  1 root root    4082 Feb  2 14:20 zend_signal.h
-rwxrwxrwx  1 root root     329 Feb 22 08:46 zend_signal.lo
-rwxrwxrwx  1 root root   29320 Feb 22 08:46 zend_signal.o
-rwxrwxrwx  1 root root    5672 Feb  2 14:20 zend_smart_str.c
-rwxrwxrwx  1 root root    5530 Feb  2 14:20 zend_smart_str.h
-rwxrwxrwx  1 root root     338 Feb 22 08:46 zend_smart_str.lo
-rwxrwxrwx  1 root root   18552 Feb 22 08:46 zend_smart_str.o
-rwxrwxrwx  1 root root    1279 Feb  2 14:20 zend_smart_str_public.h
-rwxrwxrwx  1 root root    4389 Feb  2 14:20 zend_smart_string.h
-rwxrwxrwx  1 root root    1392 Feb  2 14:20 zend_smart_string_public.h
-rwxrwxrwx  1 root root   10852 Feb  2 14:20 zend_sort.c
-rwxrwxrwx  1 root root    1636 Feb  2 14:20 zend_sort.h
-rwxrwxrwx  1 root root     323 Feb 22 08:45 zend_sort.lo
-rwxrwxrwx  1 root root   28488 Feb 22 08:45 zend_sort.o
-rwxrwxrwx  1 root root    3983 Feb  2 14:20 zend_stack.c
-rwxrwxrwx  1 root root    2360 Feb  2 14:20 zend_stack.h
-rwxrwxrwx  1 root root     326 Feb 22 08:45 zend_stack.lo
-rwxrwxrwx  1 root root   13312 Feb 22 08:45 zend_stack.o
-rwxrwxrwx  1 root root    7212 Feb  2 14:20 zend_stream.c
-rwxrwxrwx  1 root root    3542 Feb  2 14:20 zend_stream.h
-rwxrwxrwx  1 root root     329 Feb 22 08:46 zend_stream.lo
-rwxrwxrwx  1 root root   24776 Feb 22 08:46 zend_stream.o
-rwxrwxrwx  1 root root   12740 Feb  2 14:20 zend_string.c
-rwxrwxrwx  1 root root   17347 Feb  2 14:20 zend_string.h
-rwxrwxrwx  1 root root     329 Feb 22 08:46 zend_string.lo
-rwxrwxrwx  1 root root   77697 Feb 23 09:51 zend_string.o
-rwxrwxrwx  1 root root   92649 Feb  2 14:20 zend_strtod.c
-rwxrwxrwx  1 root root    1854 Feb  2 14:20 zend_strtod.h
-rwxrwxrwx  1 root root     329 Feb 22 08:46 zend_strtod.lo
-rwxrwxrwx  1 root root  117472 Feb 22 08:46 zend_strtod.o
-rwxrwxrwx  1 root root    3499 Feb  2 14:20 zend_strtod_int.h
-rwxrwxrwx  1 root root    8172 Feb  2 14:20 zend_ts_hash.c
-rwxrwxrwx  1 root root    5731 Feb  2 14:20 zend_ts_hash.h
-rwxrwxrwx  1 root root     332 Feb 22 08:45 zend_ts_hash.lo
-rwxrwxrwx  1 root root   42888 Feb 22 08:45 zend_ts_hash.o
-rwxrwxrwx  1 root root    3091 Feb  2 14:20 zend_type_info.h
-rwxrwxrwx  1 root root   40632 Feb 23 03:41 zend_types.h
-rwxrwxrwx  1 root root    4739 Feb  2 14:20 zend_variables.c
-rwxrwxrwx  1 root root    3273 Feb  2 14:20 zend_variables.h
-rwxrwxrwx  1 root root     338 Feb 22 08:45 zend_variables.lo
-rwxrwxrwx  1 root root   43816 Feb 22 08:45 zend_variables.o
-rwxrwxrwx  1 root root   43224 Feb  2 14:20 zend_virtual_cwd.c
-rwxrwxrwx  1 root root   12734 Feb  2 14:20 zend_virtual_cwd.h
-rwxrwxrwx  1 root root     344 Feb 22 08:46 zend_virtual_cwd.lo
-rwxrwxrwx  1 root root   80456 Feb 22 08:46 zend_virtual_cwd.o
-rwxrwxrwx  1 root root    1952 Feb  2 14:20 zend_vm.h
-rwxrwxrwx  1 root root  271416 Feb  2 14:20 zend_vm_def.h
-rwxrwxrwx  1 root root 2025584 Feb  2 14:20 zend_vm_execute.h
-rwxrwxrwx  1 root root    3616 Feb  2 14:20 zend_vm_execute.skl
-rwxrwxrwx  1 root root  146220 Feb  2 14:20 zend_vm_gen.php
-rwxrwxrwx  1 root root   87968 Feb  2 14:20 zend_vm_handlers.h
-rwxrwxrwx  1 root root    8522 Feb  2 14:20 zend_vm_opcodes.c
-rwxrwxrwx  1 root root   12080 Feb  2 14:20 zend_vm_opcodes.h
-rwxrwxrwx  1 root root     341 Feb 22 08:45 zend_vm_opcodes.lo
-rwxrwxrwx  1 root root   17408 Feb 22 08:45 zend_vm_opcodes.o
-rwxrwxrwx  1 root root    3212 Feb  2 14:20 zend_vm_trace_handlers.h
-rwxrwxrwx  1 root root    2654 Feb  2 14:20 zend_vm_trace_map.h
-rwxrwxrwx  1 root root    6578 Feb  2 14:20 zend_weakrefs.c
-rwxrwxrwx  1 root root    1445 Feb  2 14:20 zend_weakrefs.h
-rwxrwxrwx  1 root root     335 Feb 22 08:46 zend_weakrefs.lo
-rwxrwxrwx  1 root root   66704 Feb 22 08:46 zend_weakrefs.o

對於沒有c語言基礎的同學看到這麼多. c .lo .o.h是發懵的不像PHP 只有一個.php格式

我先介紹下c語言中的檔案類型和後綴

c檔案:主要每個模組的原代碼都在c檔中。

h文件:每个c文件都跟着一个h文件,h文件的作用是放着c文件中函数的声明,结构体的定义,宏的定义等。

o文件:目标文件。每个文件经过编译都会形成一个目标文件(二进制文件),多个目标文件链接后才能形成可执行文件。

o文件如何形成: gcc -c a.c (gcc 以后会用到 再说)

.so文件

.so文件就不一样了,它不是简单的.o文件打了一个包,它是一个ELF格式的文件,也就是linux的可执行文件。

.so文件可以用于多个进程的共享使用(位置无关的才行),所以又叫共享库文件。程序在使用它的时候,会在运行时把它映射到自己进程空间的某一处,其不在使用它的程序中。

.lo文件 libtool生成的文件,被libtool用来生成共享库的. libtool隐藏了PIC的flag的复杂性,而采用了分离的库对象文件,以“.lo”代替“.o”结尾。在不需要共享库的系统上,这些库文件等同于标准的目标文件

所有以 我们只需要看 .h 和.c就行了 其他的 文件我们想看也看不懂

其中变量的结构体定义和宏定义 在 zend_types.h 中

至于什么是结构体 什么是宏 一会再讲

[root@2890cf458ee2 Zend]# vim zend_types.h

其中前部分代码是这样的

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 2.00 of the Zend license,     |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.zend.com/license/2_00.txt.                                |
  11    | If you did not receive a copy of the Zend license and are unable to  |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@zend.com so we can mail you a copy immediately.              |
  14    +----------------------------------------------------------------------+
  15    | Authors: Andi Gutmans <andi@php.net>                                 |
  16    |          Zeev Suraski <zeev@php.net>                                 |
  17    |          Dmitry Stogov <dmitry@php.net>                              |
  18    |          Xinchen Hui <xinchen.h@zend.com>                            |
  19    +----------------------------------------------------------------------+
  20 */
  21
  22 #ifndef ZEND_TYPES_H
  23 #define ZEND_TYPES_H
  24
  25 #include "zend_portability.h"
  26 #include "zend_long.h"
  27
  28 #ifdef __SSE2__
  29 # include <mmintrin.h>
  30 # include <emmintrin.h>
  31 #endif
  32
  33 #ifdef WORDS_BIGENDIAN
  34 # define ZEND_ENDIAN_LOHI(lo, hi)          hi; lo;
  35 # define ZEND_ENDIAN_LOHI_3(lo, mi, hi)    hi; mi; lo;
  36 # define ZEND_ENDIAN_LOHI_4(a, b, c, d)    d; c; b; a;
  37 # define ZEND_ENDIAN_LOHI_C(lo, hi)        hi, lo
  38 # define ZEND_ENDIAN_LOHI_C_3(lo, mi, hi)  hi, mi, lo,
  39 # define ZEND_ENDIAN_LOHI_C_4(a, b, c, d)  d, c, b, a
  40 #else
  41 # define ZEND_ENDIAN_LOHI(lo, hi)          lo; hi;
  42 # define ZEND_ENDIAN_LOHI_3(lo, mi, hi)    lo; mi; hi;
  43 # define ZEND_ENDIAN_LOHI_4(a, b, c, d)    a; b; c; d;
  44 # define ZEND_ENDIAN_LOHI_C(lo, hi)        lo, hi
  45 # define ZEND_ENDIAN_LOHI_C_3(lo, mi, hi)  lo, mi, hi,
  46 # define ZEND_ENDIAN_LOHI_C_4(a, b, c, d)  a, b, c, d
  47 #endif
  48
  49 typedef unsigned char zend_bool;
  50 typedef unsigned char zend_uchar;
  51
  52 typedef enum {
  53   SUCCESS =  0,
  54   FAILURE = -1,         /* this MUST stay a negative number, or it may affect functions! */
  55 } ZEND_RESULT_CODE;
  56
  57 #ifdef ZEND_ENABLE_ZVAL_LONG64
  58 # ifdef ZEND_WIN32
  59 #  define ZEND_SIZE_MAX  _UI64_MAX
  60 # else
  61 #  define ZEND_SIZE_MAX  SIZE_MAX
  62 # endif
  63 #else
  64 # if defined(ZEND_WIN32)
  65 #  define ZEND_SIZE_MAX  _UI32_MAX
  66 # else
  67 #  define ZEND_SIZE_MAX SIZE_MAX
  68 # endif
  69 #endif
  70
  71 typedef intptr_t zend_intptr_t;
  72 typedef uintptr_t zend_uintptr_t;
  73
  74 #ifdef ZTS
  75 #define ZEND_TLS static TSRM_TLS
  76 #define ZEND_EXT_TLS TSRM_TLS
  77 #else
  78 #define ZEND_TLS static
  79 #define ZEND_EXT_TLS
  80 #endif
  81
  82 typedef struct _zend_object_handlers zend_object_handlers;
  83 typedef struct _zend_class_entry     zend_class_entry;
  84 typedef union  _zend_function        zend_function;
  85 typedef struct _zend_execute_data    zend_execute_data;
  86
  87 typedef struct _zval_struct     zval;
  88
  89 typedef struct _zend_refcounted zend_refcounted;
  90 typedef struct _zend_string     zend_string;
  91 typedef struct _zend_array      zend_array;
  92 typedef struct _zend_object     zend_object;
  93 typedef struct _zend_resource   zend_resource;
  94 typedef struct _zend_reference  zend_reference;
  95 typedef struct _zend_ast_ref    zend_ast_ref;
  96 typedef struct _zend_ast        zend_ast;
  97
  98 typedef int  (*compare_func_t)(const void *, const void *);
  99 typedef void (*swap_func_t)(void *, void *);
 100 typedef void (*sort_func_t)(void *, size_t, size_t, compare_func_t, swap_func_t);
 101 typedef void (*dtor_func_t)(zval *pDest);
 102 typedef void (*copy_ctor_func_t)(zval *pElement);

这个#开始的内容并不是注释 只需要大概了解下 以下内容

#空指令,无任何效果
#include开头 -------包含一个源代码文件
#define开头 -------定义宏
#undef开头 -------取消已定义的宏
#if开头 -------如果给定条件为真,则编译下面代码
#ifdef开头 -------如果宏已经定义,则编译下面代码
#ifnde开头 -------f如果宏没有定义,则编译下面代码
#elif开头 -------如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
#endif开头 -------结束一个#if……#else条件编译块
#error开头 -------停止编译并显示错误信息

其实就是头文件 无实际寓意 比如#ifdef WORDS_BIGENDIAN 这是大小端的 判断

 196 struct _zval_struct {
 197         zend_value        value;                        /* value */
 198         union {
 199                 struct {
 200                         ZEND_ENDIAN_LOHI_3(
 201                                 zend_uchar    type,                     /* active type */
 202                                 zend_uchar    type_flags,
 203                                 union {
 204                                         uint16_t  extra;        /* not further specified */
 205                                 } u)
 206                 } v;
 207                 uint32_t type_info;
 208         } u1;
 209         union {
 210                 uint32_t     next;                 /* hash collision chain */
 211                 uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */
 212                 uint32_t     opline_num;           /* opline number (for FAST_CALL) */
 213                 uint32_t     lineno;               /* line number (for ast nodes) */
 214                 uint32_t     num_args;             /* arguments number for EX(This) */
 215                 uint32_t     fe_pos;               /* foreach position */
 216                 uint32_t     fe_iter_idx;          /* foreach iterator index */
 217                 uint32_t     access_flags;         /* class constant access flags */
 218                 uint32_t     property_guard;       /* single property guard */
 219                 uint32_t     constant_flags;       /* constant flags */
 220                 uint32_t     extra;                /* not further specified */
 221         } u2;
 222 };

这部分是 变量 的核心 代码

C语言结构体(Struct)从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,是由 int、char、float 等基本类型组成的。你可以认为结构体是一种聚合类型。在实际开发中,我们可以将一组类型不同的、但是用来描述同一件事物的变量放到结构体中。例如,在校学生有姓名、年龄、身高、成绩等属性,学了结构体后,我们就不需要再定义多个变量了,将它们都放到结构体中即可。 有点类似于 PHP里的对象?

结构体里面用;进行 分割 每个子变量

可以看出来 _zval_struct 结构体 包括三个变量部分 (以单下划线(_)表明是标准库的变量

双下划线(__) 开头表明是编译器的变量)

分别为 value u1 u2

(你要这样 理解 197行中 zend_value value; 这行代码中 zend_value是变量类型 value 是名字 )

结构体里第一个值类型名为 zend_value 这应该不是一个变量 我们搜一下

/zend_value

代码在176处定义了 zend_value

 176 typedef union _zend_value {
 177         zend_long         lval;                         /* long value */
 178         double            dval;                         /* double value */
 179         zend_refcounted  *counted;
 180         zend_string      *str;
 181         zend_array       *arr;
 182         zend_object      *obj;
 183         zend_resource    *res;
 184         zend_reference   *ref;
 185         zend_ast_ref     *ast;
 186         zval             *zv;
 187         void             *ptr;
 188         zend_class_entry *ce;
 189         zend_function    *func;
 190         struct {
 191                 uint32_t w1;
 192                 uint32_t w2;
 193         } ww;
 194 } zend_value;

联合体 / union

union使用方法和struct非常相似,唯一的不同是struct变量所占内存长度是各成员的内存之和,而union内存长度则是占内存最大的成员的长度,也就是说union的几个成员变量是共用一块内存的。

简单点来说就是

假如

struct a里面 包含 变量a1 内存占用为1 a2 内存占用为2 那么 struct a 总占用内存为1+2=3

union b里面 包含 变量b1 内存占用为1 b2 内存占用为2 那么 union b 总占用内存为2

继续看 zend_value

zend_long         lval;          //整型
double            dval;          //浮点型
zend_refcounted  *counted;     //获取不同类型结构的gc头部的指针
zend_string      *str;        //string字符串 的指针
zend_array       *arr;        //数组指针
zend_object      *obj;        //object 对象指针
zend_resource    *res;         ///资源类型指针
zend_reference   *ref;       //引用类型指针   比如你通过&$c  定义的
zend_ast_ref     *ast;     // ast 指针  线程安全 相关的 内核使用的  
zval             *zv;   // 指向另外一个zval的指针  内核使用的
void             *ptr;   //指针  ,通用类型  内核使用的
zend_class_entry *ce;    //类 ,内核使用的
zend_function    *func;   // 函数 ,内核使用的
struct {
 uint32_t w1;//自己定义的。 无符号的32位整数
 uint32_t w2;//同上
} ww;

lval 和 dval 分别为 整型和 浮点型 剩下的 为* 开头的 指针

什么是指针?

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

type *var-name;

在这里,type 是指针的基类型,它必须是一个有效的 C 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。以下是有效的指针声明:

  int    *ip;    /* 一个整型的指针 
 double *dp;    /* 一个 double 型的指针 
 float  *fp;    /* 一个浮点型的指针
  char   *ch;    /* 一个字符型的指针

所有实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,对应指针的值的类型都是一样的,都是一个代表内存地址的长的十六进制数。

不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。指针占用8个字节

所以value 联合体需要的内存是 8 个字节

继续看u1

union {
      struct {
        //这是个宏 c语言里面 这种全部都是大写的 变量大部分是宏
        ZEND_ENDIAN_LOHI_3(
        ///变量的类型
        zend_uchar    type,                    
        //类型掩码,每个类型会有不同的属性 内存管理会用到
        zend_uchar    type_flags,
        //这个不知道是干嘛的 估计是预留以后拓展?
        union {
           uint16_t  extra;        /* not further specified */
        } u)
      } v;
     //一个无符号的整型 记录 变量类型的
    uint32_t type_info;
} u1;

其实v 里面就是一个宏 (你可以理解为PHP里面的构造方法 )是为了兼容大小字节序,小字节序就是下面的顺序 大字节序是下面的4个顺序翻转

type_info是用来记录变量的类型 占用4个字节 每个字节对于v中一个成员

所以 u1占用 4个字节 加上 value 8个字节 4+8=12个字节

value 本来应该占 8 个字节,但是由于内存对齐,哪怕只增加一个字节,实际上也是占用 16 个字节(使用一个字节就意味着需要额外的 8 个字节)。但是显然我们并不需要 8 个字节来存储一个 type 字段,所以我们在 u1 的后面增加了了一个名为 u2 的联合体。默认情况下是用不到的,需要使用的时候可以用来存储 4 个字节的数据。这个联合体可以满足不同场景下的需求。

什么是内存对齐?

将每一个数据的起始位置,在内存的对其位置处。

为什么要内存对齐?

无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。

这个u2 是扩展用的 一般不会用到

比如 next 在散列表里解决哈希冲突会用到 (现在给你说hash冲突你会懵)

再比如 fe_pos 会在 foreach遍历时候用到

  union {
  uint32_t     next;                 /* hash collision chain */
  uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */
  uint32_t     opline_num;           /* opline number (for FAST_CALL) */
  uint32_t     lineno;               /* line number (for ast nodes) */
  uint32_t     num_args;             /* arguments number for EX(This) */
  uint32_t     fe_pos;               /* foreach position */
  uint32_t     fe_iter_idx;          /* foreach iterator index */
  uint32_t     access_flags;         /* class constant access flags */
  uint32_t     property_guard;       /* single property guard */
  uint32_t     constant_flags;       /* constant flags */
  uint32_t     extra;                /* not further specified */
  } u2;

所以 PHP7 以上的 zval_struct 占用16个字节 非常小了!

▏本文经原作者PHP崔雪峰同意,发布在php中文网,原文地址:https://zhuanlan.zhihu.com/p/352507796

以上是解析PHP底層內核原始碼之變數 (一)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:zhihu.com。如有侵權,請聯絡admin@php.cn刪除