深入理解PHP原理之变量声明

往期精选(欢迎转发~~)

在PHP中没有对常规变量的声明操作,如果要使用一个变量,直接进行赋值操作即可,因为PHP在赋值操作的同时已经进行声明操作,那么PHP是怎样在赋值前进行声明的呢?
  在博文《深入理解PHP原理之变量赋值》中其实已经提到过变量的声明,但是讲述的不够透彻,下面主要通过词法分析、语法分析和获取左值和右值的过程,来讲述变量声明的原理。
  下面是一个简单的变量赋值操作:

$a = 'hello world';

在赋值前,我们先看看变量a是怎样存储的,之前我们在《深入理解PHP原理之变量赋值》中讲过,是这么描述变量a的“因为变量名a其实有一个指针ptr_a,每次初始化一个变量时,系统会先开辟一块内存,将变量的值保持在zval中,然后将变量a和对应的指针ptr_a保持在数值中,同时让ptr_a指向zval的首地址”,其实在执行的过程中,变量名及指针主要存储_zend_executor_globals的符号表中,_zend_executor_globals的结构如下:

struct _zend_executor_globals {
	...
	/* symbol table cache */
	HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
	HashTable **symtable_cache_limit;
	HashTable **symtable_cache_ptr;
	zend_op **opline_ptr;
	HashTable *active_symbol_table; /* active symbol table */
	HashTable symbol_table; /* main symbol table */
	HashTable included_files; /* files already included */
	...
}

其中active_symbol_table和symbol_table中保存不同类型变量的变量名,opline_ptr是指向变量值的指针,变量a就保存在该数组中。
  知道了变量的存储方法,我们还是回到之前的赋值语句,该语句经过词法分析和语法分析后,大致会解析为以下的条件语句:

FETCH_W local !0, 'a'
ASSIGN !0, 'hello+world'

第一行是将变量a保存到临时变量!0(前面的感叹号,表示数据放在缓存),第二行是进行赋值操作,在赋值前需要获取左值和右值,代码如下:

zval *value = &opline->op2.u.constant;
zval **variable_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1,EX(Ts), BP_VAR_W TSRMLS_CC);

由于右值为一个数值,我们可以理解为一个常量,则直接取操作数存储的constant字段,左值是通过 _get_zval_ptr_ptr_cv函数获取zval值,代码如下:

static zend_always_inline zval **_get_zval_ptr_ptr_cv(const znode *node, const
temp_variable *Ts, int type TSRMLS_DC)
{
	zval ***ptr = &CV_OF(node->u.var);
	if (UNEXPECTED(*ptr == NULL)) {
		return _get_zval_cv_lookup(ptr, node->u.var, type TSRMLS_CC);
	}
	return *ptr;
}
// 函数中的CV_OF宏定义
#define CV_OF(i) (EG(current_execute_data)->CVs[i])

该函数中先调用CV_OF(node->u.var),CV_OF是个宏,展开后其实调用的是CVs,那什么是CVs呢?它其实就是个缓存,以数组的形式缓存变量所在HashTable的值,获取变量的值前,先从缓存中取,用于提高效率(是不是可以和之前提到的“FETCH_W local !0, ‘a’”对应起来呢,!0表示数据在缓存)。如果在缓存中没有获取到,调用方法_get_zval_cv_lookup(),该方法通过EG(active_symbol_table)表查找变量。
  上面是在变量赋值前进行的一些操作,我把他们定义为“变量的声明”,具体赋值操作,可以参考我之前的博文《深入理解PHP原理之变量赋值》,里面讲的非常详细。
  可能大家感觉有点晕,我总结一下,当变量进行赋值时,如$a=1,先将变量a放在缓存中,这个变量包含变量名a和指针(此时的指针可以理解为空指针,因为还没有给它赋值),然后是获取左值和右值,右值的获取很easy,左值的获取分2步,即先到缓存中找,如果没有,就到哈希表中找,最后就是赋值操作,结束!

参考:http://www.php-internals.com/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值