<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>风雪之隅 &#187; global</title>
	<atom:link href="http://www.laruence.com/tag/global/feed" rel="self" type="application/rss+xml" />
	<link>http://www.laruence.com</link>
	<description>PHP语言, PHP扩展, Zend引擎相关的研究,技术,新闻分享 - 左手代码 右手诗</description>
	<lastBuildDate>Wed, 08 Feb 2012 05:12:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>PHP源码分析之Global关键字</title>
		<link>http://www.laruence.com/2008/08/24/377.html</link>
		<comments>http://www.laruence.com/2008/08/24/377.html#comments</comments>
		<pubDate>Sun, 24 Aug 2008 05:32:32 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[global]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=377</guid>
		<description><![CDATA[<p>闲来无事，就系统的从PHP的词法分析，语法分析，opcodes生成，执行，整个流程，详细的分析了global关键字的实现。</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2008/08/24/377.html"  title="Permanet Link to PHP源码分析之Global关键字" >http://www.laruence.com/2008/08/24/377.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>闲来无事，就系统的从PHP的词法分析，语法分析，opcodes生成，执行，整个流程，详细的分析了global关键字的实现。</p>
<p>当你在脚本中写下:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
    $var = &quot;laruence&quot;;
    function sample(){
        global $var;
    }
?&gt;
</pre>
<p>的时候，你知道PHP是怎么实现在函数作用域找到全局变量的么？ </p>
<p>在我前面的文章中(<a href="http://www.laruence.com/2008/06/18/221.html" >深入理解PHP原理之Opcodes</a>)讲过, PHP的执行，经历了如下几个阶段：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)

2. Parsing, 将Tokens转换成简单而有意义的表达式

3. Compilation, 将表达式编译成Opocdes

4. Execution, 顺次执行Opcodes，每次一条，从而实现PHP脚本的功能。
</pre>
<p>那么，第一阶段，自然就是Scanning了， 在词法分析阶段，我们的</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
global $var;
</pre>
<p>会被解析为：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
    T_GLOBAL  var;
</pre>
<p>接下来是parsing阶段：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
T_GLOBAL var;
</pre>
<p>yacc经过规则：</p>
<pre name="code"  class="sh_shell"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
	statement:
		|  T_GLOBAL global_var_list ';'
		....

	global_var_list:
        global_var_list ',' global_var  { zend_do_fetch_global_variable(&amp;$3, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); }
    |   global_var                      { zend_do_fetch_global_variable(&amp;$1, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); }
;
</pre>
<p>其中, zend_do_fetch_global_variable是真正生成opcode的函数：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
      zend_op  *opline;
      ......
      opline-&gt;opcode = ZEND_FETCH_W;
      opline-&gt;result.op_type = IS_VAR;
	  ......
      opline-&gt;op2.u.EA.type = ZEND_FETCH_GLOBAL_LOCK;
</pre>
<p>而对于ZEND_FETCH_W的op_handler是：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
	ZEND_VM_HANDLER(83, ZEND_FETCH_W, CONST|TMP|VAR|CV, ANY)
	{
    	ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_W);
	}
</pre>
<p>  我们来看看zend_fetch_var_adress_helper:</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
        .....
        target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), type, varname TSRMLS_CC);
/*
        if (!target_symbol_table) {
            ZEND_VM_NEXT_OPCODE();
        }
*/
        if (zend_hash_find(target_symbol_table, varname-&gt;value.str.val, varname-&gt;value.str.len+1, (void **) &amp;retval) == FAILUR
E) {
            switch (type) {
                case BP_VAR_R:
                case BP_VAR_UNSET:
                    zend_error(E_NOTICE,&quot;Undefined variable: %s&quot;, Z_STRVAL_P(varname));
                    /* break missing intentionally */
                case BP_VAR_IS:
                    retval = &amp;EG(uninitialized_zval_ptr);
                    break;
                case BP_VAR_RW:
                    zend_error(E_NOTICE,&quot;Undefined variable: %s&quot;, Z_STRVAL_P(varname));
                    /* break missing intentionally */
                case BP_VAR_W: {
                        zval *new_zval = &amp;EG(uninitialized_zval);

                        new_zval-&gt;refcount++;
                        zend_hash_update(target_symbol_table, varname-&gt;value.str.val, varname-&gt;value.str.len+1, &amp;new_zval, siz
eof(zval *), (void **) &amp;retval);
                    }
                    break;
                EMPTY_SWITCH_DEFAULT_CASE()
            }
        }
</pre>
<p>可以看出，核心就是zend_get_targer_symbol_table这个函数了：</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
static inline HashTable *zend_get_target_symbol_table(zend_op *opline, temp_variable *Ts, int type, zval *variable TSRMLS_DC)
{
    switch (opline-&gt;op2.u.EA.type) {
        case ZEND_FETCH_LOCAL:
            return EG(active_symbol_table);
            break;
        case ZEND_FETCH_GLOBAL:
        case ZEND_FETCH_GLOBAL_LOCK:
            return &amp;EG(symbol_table);
            break;
        case ZEND_FETCH_STATIC:
            if (!EG(active_op_array)-&gt;static_variables) {
                ALLOC_HASHTABLE(EG(active_op_array)-&gt;static_variables);
                zend_hash_init(EG(active_op_array)-&gt;static_variables, 2, NULL, ZVAL_PTR_DTOR, 0);
            }
            return EG(active_op_array)-&gt;static_variables;
            break;
        EMPTY_SWITCH_DEFAULT_CASE()
    }
    return NULL;
}
</pre>
<p>  恩，问题清楚了，也就是说， 如果你global了一个变量，那么Zend就会去全局symbol_table去寻找，如果找不到，就会在全局symbol_table中分配相应的变量。<br/>
  通过这样的机制，实现了全局变量。<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_shell.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2008/08/24/377.html" >2008/08/24</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >guoxiaod</a> writes: 之前我们遇到了一个问题：
关于PHP class 的顺序的问题，问题如下:
hello();

提示找不到 class b .

这个问题，是什么原因呢?</li><li><a href="http://www.laruence.com/2008/08/24/377.html" >2008/08/24</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >guoxiaod</a> writes: 哎，居然，把 &lt;? 过滤掉了。</li><li><a href="http://www.laruence.com/2008/08/24/377.html" >2008/08/24</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >guoxiaod</a> writes: 再发一边。
&lt;?php
class a extends b {
  public function hello(){echo "ok1";}
};
class b extends c {
  public function hello(){echo "ok2";}
};
class c {
  public function hello (){echo "ok3";}
};


$a  = new a();
$a-&gt;hello();</li><li><a href="http://www.laruence.com/2008/08/24/377.html" >2008/08/24</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 这个问题确实奇怪， 一层继承的时候就没有问题。估计是PHP5的一个bug。
回头我研究研究。</li><li><a href="http://www.laruence.com/2008/08/24/377.html" >2008/08/25</a>, <a href="http://www.blankyao.cn"  rel="external nofollow"  class="url" >blankyao</a> writes: 那篇讲多重继承的bug的文章呢？只在阅读器上看到了....</li><li><a href="http://www.laruence.com/2008/08/24/377.html" >2008/08/25</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 恩，因为刚才我发现我的思路可能有点问题，所以又重新验证了一下，这个过程中怕误导别人，就先给隐藏了。 现在好了。</li><li><a href="http://www.laruence.com/2008/08/24/377.html" >2010/10/03</a>, xinbe writes: 那請問用$GLOBALS['var']
跟global $var
哪個會比較快呢？</li><li><a href="http://www.laruence.com/2008/08/24/377.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=206"  rel="external nofollow"  class="url" >PHP源码分析之Global关键字 | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/08/24/377.html [...]</li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2009/12/26/1198.html"  title="深入理解PHP原理之变量生命期(一)" >深入理解PHP原理之变量生命期(一)</a></li><li><a href="http://www.laruence.com/2009/10/15/1131.html"  title="提升PHP性能之改变Zend引擎分发方式" >提升PHP性能之改变Zend引擎分发方式</a></li><li><a href="http://www.laruence.com/2012/02/08/2528.html"  title="PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)" >PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)</a></li><li><a href="http://www.laruence.com/2012/02/02/2515.html"  title="我们什么时候应该使用异常?" >我们什么时候应该使用异常?</a></li><li><a href="http://www.laruence.com/2012/02/01/2503.html"  title="使用exit(-1)为什么得到255退出码?" >使用exit(-1)为什么得到255退出码?</a></li><li><a href="http://www.laruence.com/2012/01/11/2482.html"  title="PHP的历史" >PHP的历史</a></li><li><a href="http://www.laruence.com/2012/01/10/2469.html"  title="如何设置一个严格30分钟过期的Session" >如何设置一个严格30分钟过期的Session</a></li><li><a href="http://www.laruence.com/2012/01/07/2453.html"  title="2012年1月全球www网站技术报告" >2012年1月全球www网站技术报告</a></li><li><a href="http://www.laruence.com/2011/12/30/2440.html"  title="PHP5.2.*防止Hash冲突拒绝服务攻击的Patch" >PHP5.2.*防止Hash冲突拒绝服务攻击的Patch</a></li><li><a href="http://www.laruence.com/2011/12/30/2435.html"  title="PHP数组的Hash冲突实例" >PHP数组的Hash冲突实例</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/08/24/377.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

