<?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="https://www.phppan.com/tag/%e8%bf%ad%e4%bb%a3%e5%99%a8/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sat, 25 Apr 2026 00:56:17 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>PHP源码阅读笔记二十四 ：iterator实现中当值为false时无法完成迭代的原因分析</title>
		<link>https://www.phppan.com/2010/04/php-source-24-iterator-false-value/</link>
		<comments>https://www.phppan.com/2010/04/php-source-24-iterator-false-value/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 00:49:11 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[foreach]]></category>
		<category><![CDATA[Iterator]]></category>
		<category><![CDATA[PHP源码]]></category>
		<category><![CDATA[迭代器]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=661</guid>
		<description><![CDATA[PHP源码阅读笔记二十四 ：iterator实现中当值为false时无法完成迭代的原因分析 在前面有一篇文章迭 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>PHP源码阅读笔记二十四 ：iterator实现中当值为false时无法完成迭代的原因分析<br />
在前面有一篇文章<a href="http://www.phppan.com/2010/04/php-iterator-and-yii-cmapiterator">迭代器的简单实现及Yii框架中的迭代器实现</a>中有一个简单的迭代器的实现，此处遗留了一个问题，当迭代的值中包含false时，使用foreach循环的时候在这个地方就结束了，原因是什么呢？<br />
<br />
在鸟哥的blog中，很久以前一篇文章对iterator的实现作了一些说明：<a href="http://www.laruence.com/2008/10/31/574.html">http://www.laruence.com/2008/10/31/574.html</a><br />
但是并没有对false的值的处理作相关说明<br />
顺着鸟哥的思路在Zend/zend_vm_execute.h文件的8131行找到相关的线索，如下所示代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">/*  */</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>iter <span style="color: #339933;">||</span> <span style="color: #009900;">&#40;</span>iter<span style="color: #339933;">-&gt;</span>index <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span> <span style="color: #339933;">&amp;&amp;</span> iter<span style="color: #339933;">-&gt;</span>funcs<span style="color: #339933;">-&gt;</span>valid<span style="color: #009900;">&#40;</span>iter TSRMLS_CC<span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> FAILURE<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #808080; font-style: italic;">/* reached end of iteration */</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>EG<span style="color: #009900;">&#40;</span>exception<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
array<span style="color: #339933;">-&gt;</span>refcount<span style="color: #339933;">--;</span>
zval_ptr_dtor<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>array<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
ZEND_VM_NEXT_OPCODE<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
ZEND_VM_JMP<span style="color: #009900;">&#40;</span>EX<span style="color: #009900;">&#40;</span>op_array<span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span>opcodes<span style="color: #339933;">+</span>opline<span style="color: #339933;">-&gt;</span>op2.<span style="color: #202020;">u</span>.<span style="color: #202020;">opline_num</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>对于实现的简单的迭代器，iter->funcs->valid(iter TSRMLS_CC) 方法调用的valid()方法，<br />
如果我们的值为false时，通过current返回的值为false，此时通过foreach访问时，遍历就在此中断了，程序会继续执行下面的代码，而不是这个循环了<br />
<br />
解决方案<br />
将数组中的key和value分开处理<br />
在valid()，rewind(),next()方法中操作key，而不是value<br />
仅在current中返回value<br />
如文章<a href="http://www.phppan.com/2010/04/php-iterator-and-yii-cmapiterator">迭代器的简单实现及Yii框架中的迭代器实现</a>中的Yii框架中的CMapIterator的实现</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2010/04/php-source-24-iterator-false-value/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP中迭代器的简单实现及Yii框架中的迭代器实现</title>
		<link>https://www.phppan.com/2010/04/php-iterator-and-yii-cmapiterator/</link>
		<comments>https://www.phppan.com/2010/04/php-iterator-and-yii-cmapiterator/#comments</comments>
		<pubDate>Sat, 24 Apr 2010 00:54:14 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Iterator]]></category>
		<category><![CDATA[PHP应用]]></category>
		<category><![CDATA[Yii框架]]></category>
		<category><![CDATA[设计模式]]></category>
		<category><![CDATA[迭代器]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=652</guid>
		<description><![CDATA[PHP中迭代器的简单实现及Yii框架中的迭代器实现 在维基百科中我们可以看到其定义如下： 迭代器有时又称光标（ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>PHP中迭代器的简单实现及Yii框架中的迭代器实现<br />
在维基百科中我们可以看到其定义如下：<br />
迭代器有时又称光标（cursor）是程式设计的软件设计模式，可在容器物件（container，例如list或vector）上遍访的接口，设计人员无需关心容器物件的内容。<br />
各种语言实作Iterator的方式皆不尽同，有些面向对象语言像Java, C#, Python, Delphi都已将Iterator的特性内建语言当中，完美的跟语言整合，我们称之隐式迭代器（implicit iterator），但像是C++语言本身就没有Iterator的特色，但STL仍利用template实作了功能强大的iterator。<br />
Iterator另一方面还可以整合Generator。有些语言将二者视为同一接口，有些语言则将之独立化。<br />
地址：http://zh.wikipedia.org/zh-cn/%E8%BF%AD%E4%BB%A3%E5%99%A8<br />
【Iterator的简单实现】</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>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
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/**
* Iterator模式的简单实现类
*/</span>
<span style="color: #000000; font-weight: bold;">class</span> sample implements Iterator <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$_items</span> <span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_items <span style="color: #339933;">=</span> <span style="color: #000088;">$data</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">current</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #990000;">current</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_items<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">next</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #990000;">next</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_items<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>   
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">key</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #990000;">key</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_items<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">rewind</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #990000;">reset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_items<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> valid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>                                                                              
        <span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #990000;">current</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/** DEMO */</span>
<span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">4</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$sa</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sample<span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$sa</span> <span style="color: #b1b100;">AS</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$row</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">,</span> <span style="color: #000088;">$row</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&lt;br /&gt;'</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>在next()方法的实现时有过纠结，一直以为这里需要返回下一个的值，<br />
这是因为一直以为这里的next就是next函数的实现，但是非也<br />
在手册中我们可以看到其定义为<br />
<strong>abstract public void Iterator::next ( void )</strong><br />
其返回值类型为<strong>void</strong><br />
所以这里我们调用next函数就可以了，没有必要返回<br />
另外，以上实现对于如下的数组是存在的问题<br />
$data = array(&#8217;0&#8242; => 11, &#8221; => 22, &#8216;s3&#8242; => 33, 0, 0, &#8221;, false, 0, 1);<br />
运行结果是输出：<br />
0 11<br />
22<br />
s3 33<br />
1 0<br />
2 0<br />
3<br />
false后面的值就没有迭代显示出来了，具体原因还不清楚，留作下回分解<br />
在yii框架中也有实现迭代器，它的实现避免了这个问题。<br />
<br />
【Yii框架中的迭代器实现】<br />
在Yii框架中的我们可以看到其迭代器的实现<br />
在collections目录下的CMapIterator.php文件中，其实现如下：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> CMapIterator implements Iterator <span style="color: #009900;">&#123;</span>
<span style="color: #009933; font-style: italic;">/**
* @var array the data to be iterated through
*/</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$_d</span><span style="color: #339933;">;</span>
<span style="color: #009933; font-style: italic;">/**
* @var array list of keys in the map
*/</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$_keys</span><span style="color: #339933;">;</span>
<span style="color: #009933; font-style: italic;">/**
* @var mixed current key
*/</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$_key</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
* Constructor.
* @param array the data to be iterated through
*/</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_d<span style="color: #339933;">=&amp;</span><span style="color: #000088;">$data</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_keys<span style="color: #339933;">=</span><span style="color: #990000;">array_keys</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
* Rewinds internal array pointer.
* This method is required by the interface Iterator.
*/</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">rewind</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>                                                                                 
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_key<span style="color: #339933;">=</span><span style="color: #990000;">reset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_keys<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
* Returns the key of the current array element.
* This method is required by the interface Iterator.
* @return mixed the key of the current array element
*/</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">key</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_key<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
* Returns the current array element.
* This method is required by the interface Iterator.
* @return mixed the current array element
*/</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">current</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_d<span style="color: #009900;">&#91;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_key<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
* Moves the internal pointer to the next array element.
* This method is required by the interface Iterator.
*/</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #990000;">next</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_key<span style="color: #339933;">=</span><span style="color: #990000;">next</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_keys<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
* Returns whether there is an element at current position.
* This method is required by the interface Iterator.
* @return boolean
*/</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> valid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_key<span style="color: #339933;">!==</span><span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'s1'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">11</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'s2'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">22</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'s3'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">33</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$it</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CMapIterator<span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$it</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$row</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$row</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&lt;br /&gt;'</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>这与之前的简单实现相比，其位置的变化是通过控制key来实现的，这种实现的作用是为了避免false作为数组值时无法迭代</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2010/04/php-iterator-and-yii-cmapiterator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
