PHP扩展开发与内核应用阅读笔记---php的作用域以及如何在扩展中定义,查找php变量

首先提供书的地址:php扩展开发与内科应用,并向作者表示感谢!同时欢迎同看此书的人加入QQ群:76761320

1:无法在函数中使用在函数外定义的变量的原因

由于php中定义的变量是存储在一个用HashTable实现的符号表里。当用户在PHP中调用一个函数或者类的方法时,内核会创建一个新的符号表并激活,这也就是为什么我们无法在函数中使用在函数外定义的变量的原因(因为它们分属两个符号表,一个当前作用域的,一个全局作用域的)。如果不是在一个函数里,则全局作用域的符号表处于激活状态。

然而我们是通过什么来找到当前作用域的符号表和全局作用域的符号表的呢?

我们现在打开php源码下的Zend/zend_globals.h文件,看一下_zend_execution_globals结构体,会在其中发现这么两个element:

struct _zend_executor_globals {
    ...
    HashTable symbol_table;
    HashTable *active_symbol_table;
    ...
};
其中的 symbol_table元素可以通过EG宏来访问,它代表着PHP的全局变量,如$GLOBALS,其实从根本上来讲,$GLOBALS不过是EG(symbol_table)的一层封装而已。 与之对应,下面的active_symbol_table元素也可以通过EG(active_symbol_table)的方法来访问,它代表的是处于当前作用域的变量符号表。

2:在扩展中创建一个php变量

我们可以先构思一下步骤:

  • 创建一个zval结构,并设置其类型。
  • 设置值为'bar'。
  • 将其加入当前作用域的符号表,只有这样用户才能在PHP里使用这个变量。
  • 具体的代码为
    zval *fooval;
 
    MAKE_STD_ZVAL(fooval);
    ZVAL_STRING(fooval, "bar", 1);
    ZEND_SET_SYMBOL( EG(active_symbol_table) ,  "foo" , fooval);

首先,我们声明一个zval指针fooval,并使用MAKE_STD_ZVAL宏来申请一块内存。然后通过ZVAL_STRING宏将值设置为‘bar’,最后使用ZEND_SET_SYMBOL将这个zval加入到当前的符号表里去,并将其label定义成foo,这样用户就可以在代码里通过$foo来使用它了。
3:在扩展中调用一个已经定义的php变量
内核提供了操作HashTable的API:zend_hash_find() 通过这个函数可以找到当前某个作用域下用户已经定义好的变量。
  • 定义了一个指向指针的指针
  • 通过zend_hash_find去EG(active_symbol_table)作用域下寻找名称为foo($foo)的变量,如果成功找到,此函数将返回SUCCESS。并把它的地址赋给我们在调用zend_hash_find()函数传递的fooval参数,也就是说此时fooval就指向了我们要找的数据。如果没有找到,那它不会对我们fooval参数做任何修改,并返回FAILURE常量。
  • if判断输出结果
  • 具体代码为:
    zval **fooval;
 
    if (zend_hash_find(
            EG(active_symbol_table), //这个参数是地址,如果我们操作全局作用域,则需要&EG(symbol_table)
            "foo",
            sizeof("foo"),
            (void**)&fooval
        ) == SUCCESS
    )
    {
        php_printf("成功发现$foo!");
    }
    else
    {
        php_printf("当前作用域下无法发现$foo.");
    }


你可能感兴趣的:(PHP扩展开发与内核应用阅读笔记---php的作用域以及如何在扩展中定义,查找php变量)