在循環(huán)結(jié)構(gòu)中,for是很常用的一種表達(dá)式,在學(xué)習(xí)python迭代器的時(shí)候,感覺很有意思,就反過來看看PHP中for和foreach是如何處理的
for和foreach簡(jiǎn)單描述
php中的for
處理方式類似于c語言,只要expr2
表達(dá)式為真,則循環(huán)會(huì)一直繼續(xù)下去:
for (expr1; expr2; expr3)
statement
php中的foreach
主要是為了遍歷數(shù)組和對(duì)象:
foreach開始執(zhí)行的時(shí)候,數(shù)組內(nèi)部的指針會(huì)自動(dòng)指向第一個(gè)單元,每進(jìn)行一次循環(huán),數(shù)組和對(duì)象的內(nèi)部指針為自動(dòng)移動(dòng)一位,盡量在移動(dòng)的時(shí)候不要修改其值.
foreach (array_expression as $value)
statement
foreach (array_expression as $key => $value)
statement
迭代器
上述的for
和foreach
描述很簡(jiǎn)單.
foreach
能夠循環(huán)任何迭代器對(duì)象,而這些對(duì)象不僅僅是數(shù)組,可以是任何類型的對(duì)象.
一個(gè)迭代器是一個(gè)對(duì)象,迭代器對(duì)象可能是一個(gè)數(shù)組,也可能是一個(gè)目錄,甚至可以是數(shù)據(jù)庫(kù)查詢結(jié)果集.
SPL(the Standard PHP Library)通過內(nèi)建的類,提供了很大數(shù)量的迭代器,從而讓代碼更有效,更可讀.
The DirectoryIterator class
try {
$iterator = new \DirectoryIterator($directory);
foreach ($iterator as $info) {
if (!$info->isDot() && $info->isFile()) {
echo $info->__toString() . "\n";
}
}
} catch (Exception $e) {
echo get_class($e) . ": " . $e->getMessage();
}
ArrayIterator
$arr = ["java", "python", "php"];
$iter = new ArrayIterator($arr);
foreach ($iter as $key => $value) {
echo $key . ": " . $value . "\n";
}
看一個(gè)另類的用法:
$val = ["shell", "python", "php"];
$arr = new \ArrayIterator($val);
while ($arr->valid()) {
echo $arr->key() . " : " . $arr->current() . ":" . $arr->offsetGet($arr->key()) . PHP_EOL;
$arr->offsetSet($arr->key(), "ok");
$arr->next();
}
print_r($arr->getArrayCopy());
next()
方法就是進(jìn)行指針移動(dòng)的關(guān)鍵
為什么使用迭代器
- 在處理具有大量數(shù)據(jù)的對(duì)象時(shí),使用迭代器比數(shù)組更有效,因?yàn)樵?code>foreach迭代數(shù)組的時(shí)候會(huì)拷貝數(shù)組對(duì)象,而SPL迭代器通過內(nèi)部封裝每一次只會(huì)輸出一個(gè)元素則更有效.
- 延遲加載,迭代器在使用的時(shí)候能夠加載僅僅需要的數(shù)據(jù)
- 迭代器真正有用點(diǎn)在于用途比較廣泛,能夠通過實(shí)現(xiàn)迭代器接口創(chuàng)造出更多的數(shù)據(jù)結(jié)構(gòu)
如何創(chuàng)建一個(gè)自定義迭代器
SPL迭代器類已經(jīng)提供了很多功能的迭代器,PHP也提供了接口Iterator
,IteratorAggregate
讓程序員創(chuàng)建自定義的迭代器類.
只要實(shí)現(xiàn)接口Iterator
的五個(gè)方法就可以創(chuàng)建一個(gè)迭代器類,rewind()
,current()
, key()
,next()
,valid()
當(dāng)?shù)_始,PHP調(diào)用rewind()
方法讓指針回到數(shù)據(jù)集開始處,通過調(diào)用valid()
方法檢查數(shù)據(jù)是否可用,假如返回為true,則調(diào)用current()
方法獲取當(dāng)前指針對(duì)應(yīng)的值,同時(shí)key()
能夠獲取到當(dāng)前指針的key,最后再調(diào)用next()
方法重復(fù)上述的流程.
class myIterator implements Iterator {
}
IteratorAggregate
Iterator
接口比較適合于創(chuàng)建一個(gè)內(nèi)部的迭代器,理想的情況下,使用IteratorAggregate
更加適合創(chuàng)建一個(gè)外部的迭代器,只要實(shí)現(xiàn)getIterator()
方法即可.
IteratorAggregate
和Iterator
的關(guān)系類似于容器和具體容器的關(guān)系
class myIteratorAggregate implements IteratorAggregate {
protected $arr = array("php", "python", "shell");
protected $type;
function __construct($type = 1) {
$this->type = $type;
}
public function getIterator() {
if ($this->type == 1)
return new ArrayIterator($this->arr);
else
return new myIterator($this->arr);
}
}
$obj = new myIteratorAggregate ;
foreach ($obj as $v) {
echo $v . "\n";
}
總結(jié):
- 理解迭代器很容易,但是創(chuàng)建一個(gè)有意義的迭代器則不容易,這就類似于學(xué)習(xí)算法可能很容易,但如何實(shí)際運(yùn)用則是另外一回事.
- 通過SPL迭代器,避免了程序員自造輪子,同時(shí)也提供了更多的數(shù)據(jù)結(jié)構(gòu).
- 至于使用數(shù)組還是迭代器,則要根據(jù)實(shí)際情況,比如從效率,可讀性等方面衡量.
- 通過SPL類和接口,PHP提供了更多擴(kuò)展,這也是PHP越來越現(xiàn)代化的證明.