php底层
PHP是弱语言类型,但是底层是如何实现的呢? 本文将简单讲一下PHP的底层实现。 首先我们来说说PHP代码的执行过程。
PHP代码的执行过程:
编译语言:
对于C语言、C++,将其编译成机器码(二进制)来运行。
在java语言中,.java被编译成.class,称为字节码,由jvm运行。
翻译语言:
解释器解释并执行。 一个典型的例子是linux shell。
解释器逐行执行命令。
PHP 有点特殊。 虽然是脚本语言,但并不是用套路来解释的。
相反,zend 虚拟机掩盖了操作系统之间的差异。
PHP代码被编译成opcode,opcode由zend虚拟机执行。
但是--opcode,一旦PHP脚本结束,opcode就被消除了。
思考:操作码可以缓存吗?
PHP本身不支持,但是apc、xcache等加速器可以实现这种效果。
php底层
PHP底层是用C语言实现的。 C语言是强类型语言,而PHP是弱类型语言。
它是如何实现的?
PHP变量的底层实现:
我们解压PHP源码包,看到如下目录
PHP 源代码
在,
核心---Zend目录执行php代码,这是zend的虚拟实现。 包括栈、数据类型、编译器等等,都是在这里实现的。
最重要的main——PHP的一些内置函数,最重要的函数都放在这里。
最大的目录ext——PHP扩展。
PHP的大部分功能都是通过扩展方式实现的。
如果您开发扩展,也将其放在 ext 目录中。
Zend 的变量表示:
答:Zend实现了zval结构
value: [Union],union的内容可能是C语言中的long、double、hashtable...
type:变量类型,IS_NULL、IS_BOOL、IS_STRING...IS_RESOURCE
引用计数_GC
is_ref_gc
喜欢:
$a = 3;
值:[长lval = 3]
类型:IS_LONG
$a = 3.5
值:[双 dval = 3.5]
类型:IS_DOUBLE
PHP解析
怀疑:
PHP中有8种数据类型,为什么zval->value联合中只有5种?
回答:
1:NULL,只需zval->type = IS_NULL即可表示,无需设置value的值。
2:BOOL类型,zval->type = IS_BOOL,则设置zval.value.lval = 1/0;
3:资源类型,资源类型往往是服务器上打开的socket,比如读文件的socket。
zval->type = IS_RESOURCE, zval->tyoe.lval = 服务器上打开的套接字号
发现:
在PHP中执行php代码,字符串类型和长度已经被缓存了。 当调用strlen时,系统可以直接返回其厚度,无需估计。
符号表---变量名册
多变的
变量的形状参与引用
注意:
当传递值形式参数时,
取:$a = 3; 以$b = $a为例,结构体没有再次形成,而是两个变量共享一个结构体。
此时两个变量指向同一个结构体,refcount_gc值为2
示例
思考:a和b指向同一个结构体,那么如果修改a或b,对方会受到影响吗?
答案:不,
因为两者,如果其中之一发生变化,就会导致结构分裂。
该结构一开始是共享的,当一方想要更改值时,该结构就会被拆分。
这个功能叫做cow,copy on write,
如下所示:
变量解析
引用形参时,双方共享一个结构体(is_ref_gc=1)
发生的变化如下图所示
分配时
引用时的一些奇怪现象
函数执行期间堆栈发生变化
当函数被调用时,会为这个函数生成一个“执行环境变量”结构体,里面存储了当前函数的名称、参数、对应的类……等等。
名为_zend_execute_data{}结构
这个结构中有两个重要的信息:
*op_array------>是函数的执行步骤
*hash_table---->symbol_table 该函数对应的符号表
想一想:1个函数递归调用自身3次,比如t
在堆栈上,必须有3个execute_data生成。 然而这3个execute_data--->对应了几个*op_array;
答:函数编译后,会生成一个*op_array,因为函数的执行逻辑是固定的。
再问:生成了多少个symbol_table?
答:生成3个符号表。
函数中的静态变量是如何生成的?
t() {
} 自己调用了3次
[t_3执行_数据] ---->[符号_表_3]
[t_2执行数据] ---->[符号表_2]
[t_1执行数据] ---->[符号表_1]
*op_array->*静态变量表
发表评论