搜尋
首頁後端開發PHP7解析PHP底層內核原始碼之變數 (一)

本篇文章介紹《解析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中文網其他相關文章!

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

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用