本篇文章给大家介绍《解析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
Atas ialah kandungan terperinci 解析PHP底层内核源码之变量 (一). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!