关闭

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

126人阅读 评论(0) 收藏 举报
分类:

  在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/

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:10630次
    • 积分:356
    • 等级:
    • 排名:千里之外
    • 原创:21篇
    • 转载:33篇
    • 译文:0篇
    • 评论:3条
    文章分类
    最新评论