注:源码版本 7.1.0
大家知道 php 是弱类型语言,而实现 php 的 C 语言是一种强类型的语言,这篇文章就来看看它是如何实现的。
PHP 变量内部实现
zend_types.h
文件
typedef union _zend_value {
zend_long lval; /* long value */
double dval; /* double value */
zend_refcounted *counted;
zend_string *str;
zend_array *arr;
zend_object *obj; // 对象
zend_resource *res;
zend_reference *ref; // 引用类型
zend_ast_ref *ast;
zval *zv;
void *ptr;
zend_class_entry *ce; // 类
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} zend_value;
zend_value
是一个联合体,占用 8 个字节,各类型根据自己的类型选择使用不同的成员。
typedef struct _zval_struct zval;
struct _zval_struct {
zend_value value; /* 变量值 */
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type, /* 标识数据类型 */
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved) /* call info for EX(This) */
} v;
uint32_t type_info;
} u1;
union {
uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* literal cache slot */
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 */
} u2;
};
PHP 通过 zval
结构体来表示一个变量,占 16 个字节,其内部嵌入一个 zend_value
的联合体表示具体变量值。
GDB 调试
下面是要调试的 PHP 代码:
<?php
// val.php
$a = 10;
echo $a;
$a = "Hello World";
echo $a;
1. 运行GDB并打上断点
- 运行 GDB
- 在
echo
处打断点(b ZEND_ECHO_SPEC_CV_HANDLER
) - 运行脚本 (
r val.php
)
2. $a=10
类型的值定义
/* regular data types */
#define IS_UNDEF 0
#define IS_NULL 1
#define IS_FALSE 2
#define IS_TRUE 3
#define IS_LONG 4
#define IS_DOUBLE 5
#define IS_STRING 6
#define IS_ARRAY 7
#define IS_OBJECT 8
#define IS_RESOURCE 9
#define IS_REFERENCE 10
n
下一步操作z->u1.v.type
为 4, 表明这是一个整型的数据(#define IS_LONG 4
)- 所以,从
z->value.lval
取值为 10
3. $a = “Hello World”
z->u1.v.type
为 6, 表明这是个字符串p z->value.str
,这是个zend_string
类型的指针- zend_string 中
val
表示字符数组的起始地址,len
表示长度,所以p *z->value.str.val@11
为 Hello World
附:GDB基础操作
命令名 | 功能 |
---|---|
r | 运行加载的二进制程序,可以指定参数 |
b | 打断点,参数可以是函数,或行数 |
c | 继续运行,直到下一个断点或程序结束 |
n | 下一步 |
s | 进入函数 |
bt | 打印调用堆栈 |
p | 打印变量 |