PHP中for和foreach背后發(fā)生了什么

在循環(huán)結(jié)構(gòu)中,for是很常用的一種表達(dá)式,在學(xué)習(xí)python迭代器的時(shí)候,感覺很有意思,就反過來看看PHP中for和foreach是如何處理的

for和foreach簡單描述

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

迭代器

上述的forforeach描述很簡單.

foreach能夠循環(huán)任何迭代器對(duì)象,而這些對(duì)象不僅僅是數(shù)組,可以是任何類型的對(duì)象.
一個(gè)迭代器是一個(gè)對(duì)象,迭代器對(duì)象可能是一個(gè)數(shù)組,也可能是一個(gè)目錄,甚至可以是數(shù)據(jù)庫查詢結(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()方法即可.

IteratorAggregateIterator的關(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)代化的證明.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • PHP 學(xué)習(xí)目錄 ├─PHP視頻教程 1 LAMP網(wǎng)站構(gòu)建 │ ├─PHP教程 1.1.1 新版視頻形式介紹│ ...
    曹淵說創(chuàng)業(yè)閱讀 16,185評(píng)論 29 417
  • 一 預(yù)定義接口 1.1 遍歷 Traversable(遍歷)接口 檢測一個(gè)類是否可以被foreach遍歷,該接口不...
    coderhu閱讀 1,226評(píng)論 0 0
  • 聽先生和幾個(gè)堂弟堂妹聊小時(shí)候的事。幾個(gè)人都說最喜歡也最感謝奶奶。 堂弟說:“奶奶那么愛干凈,卻總是允許我們把家里弄...
    羽宙兒閱讀 416評(píng)論 0 0
  • 京城秋涼落葉花,只剩黃綠冷天涯。 山中還有紅楓美,曇花一現(xiàn)為晚霞。
    老槐樹閱讀 149評(píng)論 0 3
  • 當(dāng)代中國經(jīng)濟(jì)高速發(fā)展,生活節(jié)奏不斷加快,我們?cè)诿τ谧非蟾咂焚|(zhì)生活的同時(shí),卻忽略了自己的健康。調(diào)查發(fā)現(xiàn),健康人群僅占...
    夕顏李閱讀 497評(píng)論 0 0