我们先想一下C程序是如何读写字面量、变量的。
#include
int main()
{
char *name = "pangudashu";
printf("%s\n", name);
return 0;
}
我们知道指针name分配在栈上,而"pangudashu"分配在常量区,那么"name"变量名分配在哪呢?
实际上C里面是不会存变量名称的,编译的过程会将变量名替换为偏移量表示:ebp - 偏移量
或esp + 偏移量
,将上面的代码转为汇编:
.LC0:
.string "pangudashu"
.text
.globl main
.type main, @function
main:
.LFB0:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq $.LC0, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call puts
movl $0, %eax
leave
可以看到movq $.LC0, -8(%rbp)
,而-8(%rbp)
就是name变量。
虽然PHP代码不会直接编译为机器码,但编译、执行的设计跟C程序是一致的,也有常量区、变量也通过偏移量访问、也有虚拟的执行栈。
在编译时就可确定且不会改变的量称为字面量,也称作常量(IS_CONST),这些值在编译阶段就已经分配zval,保存在zend_op_array->literals
数组中(对应c程序的常量存储区),访问时通过_zend_op_array->literals + 偏移量
读取,举个例子:
$a = 56;
$b = "hello";
56
通过(zval*)(_zend_op_array->literals + 0)
取到,hello
通过(zval*)(_zend_op_array->literals + 16)
取到,具体变量的读写操作将在执行阶段详细分析,这里只分析编译阶段的操作。