<?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; 腾讯笔试题</title>
	<atom:link href="http://www.laruence.com/tag/%e8%85%be%e8%ae%af%e7%ac%94%e8%af%95%e9%a2%98/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>关于一笔试题(Iterator模式)</title>
		<link>http://www.laruence.com/2008/10/31/574.html</link>
		<comments>http://www.laruence.com/2008/10/31/574.html#comments</comments>
		<pubDate>Fri, 31 Oct 2008 08:38:48 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[iterator]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php源码]]></category>
		<category><![CDATA[腾讯笔试题]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=574</guid>
		<description><![CDATA[<p>中午的时候，收到一封求教信，是关于这样的一道腾讯的面试题：
<blockquote> 
使对象可以像数组一样进行foreach循环，要求属性必须是私有。 
</blockquote>
</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/10/31/574.html"  title="Permanet Link to 关于一笔试题(Iterator模式)" >http://www.laruence.com/2008/10/31/574.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>中午的时候，收到一封求教信，是关于这样的一道面试题：</p>
<blockquote><p>
使对象可以像数组一样进行foreach循环，要求属性必须是私有。
</p></blockquote>
<p>  刚接触到题的时候，我也没有考虑到Iterator模式，试了几个一般想法，失败以后。。。。就直接去翻看了foreach的源码实现，期望发现foreach处理对象的时候是否有什么特殊性，可以做为突破口。</p>
<p>   跟踪了半天以后发现了核心逻辑中的一个奇怪的switch:</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;">
switch (zend_iterator_unwrap(array, &amp;iter TSRMLS_CC)) {
        default:
        case ZEND_ITER_INVALID:
			.....
			break
        case ZEND_ITER_PLAIN_OBJECT: {
           	......
            break;
	case ZEND_ITER_PLAIN_ARRAY:
            .....
            break;

        case ZEND_ITER_OBJECT:
            ......
            break;
}
</pre>
<p>从这个结构，我们可以看到，对象分为ZEND_ITER_OBJECT和ZEND_ITER_PLAIN_OBJECT, 这是什么意思呢？</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;">
ZEND_API enum zend_object_iterator_kind zend_iterator_unwrap(
    zval *array_ptr, zend_object_iterator **iter TSRMLS_DC)
{
    switch (Z_TYPE_P(array_ptr)) {
        case IS_OBJECT:
            if (Z_OBJ_HT_P(array_ptr) == &amp;iterator_object_handlers) {
                *iter = (zend_object_iterator *)zend_object_store_get_object(array_ptr TSRMLS_CC);
                return ZEND_ITER_OBJECT;
            }
            if (HASH_OF(array_ptr)) {
                return ZEND_ITER_PLAIN_OBJECT;
            }
            return ZEND_ITER_INVALID;

        case IS_ARRAY:
            if (HASH_OF(array_ptr)) {
                return ZEND_ITER_PLAIN_ARRAY;
            }
            return ZEND_ITER_INVALID;

        default:
            return ZEND_ITER_INVALID;
    }
}
</pre>
<p>
这就要讲到PHP的内置接口Iterator了，PHP5开始支持了接口， 并且内置了Iterator接口， 所以如果你定义了一个类，并实现了Iterator接口，那么你的这个类对象就是ZEND_ITER_OBJECT,否则就是ZEND_ITER_PLAIN_OBJECT.</p>
<p>	对于ZEND_ITER_PLAIN_OBJECT的类，foreach会通过HASH_OF获取该对象的默认属性数组，然后对该数组进行foreach.<br/>
而对于ZEND_ITER_OBJECT的类对象，则会通过调用对象实现的Iterator接口相关函数来进行foreach， 所以， 对于这道笔试题， 可以作出如下的答案：
</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;">
class sample implements Iterator
{
    private $_items = array(1,2,3,4,5,6,7);

    public function __construct() {
                  ;//void
    }
    public function rewind() { reset($this-&gt;_items); }
    public function current() { return current($this-&gt;_items); }
    public function key() { return key($this-&gt;_items); }
    public function next() { return next($this-&gt;_items); }
    public function valid() { return ( $this-&gt;current() !== false ); }
}

$sa = new sample();
foreach($sa as $key =&gt; $val){
    print $key . &quot;=&gt;&quot; .$val;
}
</pre>
<p>
以上代码在我的php 5.3下运行正常。
</p>
<p><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_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.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/10/31/574.html" >2008/10/31</a>, <a href="http://syre.blogbus.com"  rel="external nofollow"  class="url" >神仙</a> writes: 哈哈
其实直接去php手册搜会更快知道怎么弄

不过这个php的源代码实现的似乎有点囧</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/10/31</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 恩，我走了弯路，我还想着是不是可以通过其他的什么方式来更简单的实现。</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/10/31</a>, <a href="http://blog.daxi8.cn"  rel="external nofollow"  class="url" >ilsanbao</a> writes: 都是牛头哇!!!</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/10/31</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: 土了， 竟然不知道SPL，惭愧。</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/10/31</a>, yzcj007 writes: "对于ZEND_ITER_OBJECT的类对象，则会通过调用对象实现的Iterator接口相关函数来进行foreach",这句话太关键了。
经验主义害死人啊，非常感谢楼主，我看明白了。
非常期待楼主出本PHP源码分析的书，从源码分析果然很好、很强大啊。</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/10/31</a>, <a href="http://www.blankyao.cn"  rel="external nofollow"  class="url" >blankyao</a> writes: 又要看源代码啊 :)</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/11/01</a>, laruence writes: 呵呵,绕了弯路,不过, 一切的一切都是可以在源码找到答案的,呵呵</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/11/01</a>, 玉面修罗 writes: 在Zend Framework源码中可以看到大量SPL的应用
在看ZF代码之前我也确实还不知道居然有SPL这个东西</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/11/03</a>, fy writes: 果然很土</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/11/03</a>, jcadam writes: 实现一个完整的迭代器不是那么容易的事情。PHP这种弱类型语言的做法比较灵活。JAVA的实现就比较复杂；C＋＋这种半弱不强的就更难一点。类型的POD,trivial判断，还有参数传导需要很多技巧......</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/11/13</a>, zvaly writes: foreach的原代码位置是哪里？楼主教一手吧 呵呵</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/11/13</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: foreach的结构相对来说比较复杂,它不是一整块的代码块,
它是在语法分析阶段, 做了一些工作.
大体就是,在语法分析阶段(zend_language_parser.y)的时候,分别通过定位,foreach开始,中间代码,结束,从而设置出一个带有的循环的OPCODES序列..大体就是这样,如果有兴趣,可以看看上面提到的源文件.</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/11/14</a>, <a href="http://hi.baidu.com/jackywdx"  rel="external nofollow"  class="url" >jackywdx</a> writes: 呵呵，这段时间也正在研究PHP源代码，比较想了解PHP的内部实现。
前几天正在想PHP是如何实现foreach循环的呢，正好搜到了。</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/11/18</a>, <a href="http://hdwong.com"  rel="external nofollow"  class="url" >Bun Wong</a> writes: 顶！</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2008/12/10</a>, laotan writes: 关于SPL的中文资料很少，只能顶着E文</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2009/02/22</a>, alexsun writes: 汗，这题是我出的，居然在这儿看到答案。。。面试题目要改一下了。</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2009/02/22</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @alexsun, 幸会,幸会~~</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2009/02/27</a>, <a href="http://www.skiyo.cn"  rel="external nofollow"  class="url" >Jessica</a> writes: getVars();
print_r($testArr);</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2009/02/27</a>, <a href="http://www.skiyo.cn"  rel="external nofollow"  class="url" >Jessica</a> writes: class test {
	private $a = 1;
	private $b = 2;
	function getVars() {
		$array = get_defined_vars();
		return $array['this'];
	}
}
$test = new test();
$testArr = $test-&gt;getVars();
print_r($testArr);</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2009/06/08</a>, Xiaoxiao writes: 这个题,其实考的就是 PHP SPL吧,不用看源码吧...</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2009/07/16</a>, <a href="http://www.9iwj.cn"  rel="external nofollow"  class="url" >儿童游戏</a> writes: 文章不错</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2009/12/22</a>, <a href="http://www.xiaoxiaozi.com"  rel="external nofollow"  class="url" >simaopig</a> writes: 话说我不知道SPL。。。残念</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2010/04/24</a>, <a href="www.phppan.com"  rel="external nofollow"  class="url" >phppan</a> writes: next方法在接口的定义中其返回值为void
abstract public void next ( void )</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2010/04/26</a>, <a href="http://www.phppan.com/2010/04/php-source-24-iterator-false-value/"  rel="external nofollow"  class="url" >PHP源码阅读笔记二十四 ：iterator实现中当值为false时无法完成迭代的原因分析 | 胖子的空间</a> writes: [...]  在鸟哥的blog中，很久以前一篇文章对iterator的实现作了一些说明：http://www.laruence.com/2008/10/31/574.html 但是并没有对false的值的处理作相关说明 [...]</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2011/02/24</a>, <a href="http://www.php-community.net"  rel="external nofollow"  class="url" >php教程</a> writes: 这个设计模式，应该起来比较难</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=327"  rel="external nofollow"  class="url" >关于一笔试题(Iterator模式) | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2008/10/31/574.html [...]</li><li><a href="http://www.laruence.com/2008/10/31/574.html" >2011/04/14</a>, Jacob writes: 最近在准备腾讯面试，看到了这个题，感觉到似乎有些问题？这样的实现只能对自己实现的迭代器遍历，且只能遍历封装好的数组属性，如果是一个已经定义好的类呢，里面的私有属性并不是封装在一个数组中，怎么遍历呢？</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/2010/02/23/1310.html"  title="Apache2中俩种设置PHP的异同" >Apache2中俩种设置PHP的异同</a></li><li><a href="http://www.laruence.com/2009/04/28/719.html"  title="用C/C++扩展你的PHP" >用C/C++扩展你的PHP</a></li><li><a href="http://www.laruence.com/2008/11/20/630.html"  title="深入理解PHP原理之foreach" >深入理解PHP原理之foreach</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></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2008/10/31/574.html/feed</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
	</channel>
</rss>

