forked from walu/phpbook
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path2.4.txt
More file actions
41 lines (40 loc) · 3.11 KB
/
2.4.txt
File metadata and controls
41 lines (40 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
变量的存储方式
2.3
2.5
#
<p>我们在前两节已经了解了PHP中变量的类型和值是怎样在内核中用C语言实现的,这一节我们将看一下内核是怎样来组织用户在PHP中定义的变量的。</p>
<p>有一点对我们扩展开发者来说非常棒,那就是用户在PHP中定义的变量我们都可以在一个HashTable中找到,当PHP中定义了一个变量,内核会自动的把它的信息储存到一个用HashTable实现的符号表里。</p>
<p>全局作用域的符号表是在调用扩展的RINIT方法(一般都是MINIT方法里)前创建的,并在RSHUTDOWN方法执行后自动销毁。</p>
<p>当用户在PHP中调用一个函数或者类的方法时,内核会创建一个新的符号表并激活之,这也就是为什么我们无法在函数中使用在函数外定义的变量的原因(因为它们分属两个符号表,一个当前作用域的,一个全局作用域的)。如果不是在一个函数里,则全局作用域的符号表处于激活状态。</p>
<p>我们现在打开Zend/zend_globals.h文件,看一下_zend_execution_globals结构体,会在其中发现这么两个element:</p>
<code c>
struct _zend_executor_globals {
...
HashTable symbol_table;
HashTable *active_symbol_table;
...
};
</code>
<p>其中的 symbol_table元素可以通过EG宏来访问,它代表着PHP的全局变量,如$GLOBALS,其实从根本上来讲,$GLOBALS不过是EG(symbol_table)的一层封装而已。</p>
<p>与之对应,下面的active_symbol_table元素也可以通过EG(active_symbol_table)的方法来访问,它代表的是处于当前作用域的变量符号表。</p>
<p>我们上边也看到了,其实这两个成员在_zend_executor_globals里虽然都代表HashTable,但一个是真正的HashTable,而另一个是一个指针。当我们在对HashTable进行操作的时候,往往是把它的地址传递给一些函数。所以,如果我们要对EG(symbol_table)的结果进行操作,往往需要对它进行求址操作然后用它的地址作为被调用函数的参数。 <p>下面我们用一段例子来解释下上面说的理论:</p>
<code php>
<?php
$foo = 'bar';
?>
</code>
<p>上面是一段PHP语言的例子,我们创建了一个变量,并把它的值设置为'bar',在以后的代码中我们便可以使用$foo变量。相同的功能我们怎样在内核中实现呢?我们可以先构思一下步骤:</p>
<p><ul>
<li>创建一个zval结构,并设置其类型。</li>
<li>设置值为'bar'。</li>
<li>将其加入当前作用域的符号表,只有这样用户才能在PHP里使用这个变量。</li>
</ul>具体的代码为:</p>
<code c>
{
zval *fooval;
MAKE_STD_ZVAL(fooval);
ZVAL_STRING(fooval, "bar", 1);
ZEND_SET_SYMBOL( EG(active_symbol_table) , "foo" , fooval);
}
</code>
<p>首先,我们声明一个zval指针,并申请一块内存。然后通过ZVAL_STRING宏将值设置为‘bar’,最后一行的作用就是将这个zval加入到当前的符号表里去,并将其label定义成foo,这样用户就可以在代码里通过$foo来使用它了。</p>