PHP關(guān)于foreach復(fù)制知識(shí)點(diǎn)總結(jié)
PHP的foreach是一個(gè)非常整潔和切中要害的語(yǔ)言結(jié)構(gòu)。仍然有些人不喜歡使用它,因?yàn)樗麄冋J(rèn)為它是緩慢的。一個(gè)通常命名的原因是foreach復(fù)制它迭代的數(shù)組。
因此,一些人建議寫(xiě):
$keys = array_keys($array); $size = count($array); for ($i = 0; $i < $size; $i++) { $key = $keys[$i]; $value = $array[$key]; // ... }
而不是更直觀(guān)和直接:
foreach ($array as $key => $value) { // ... }
這里有兩個(gè)問(wèn)題:
Microoptimization是不好的。通常,它只會(huì)浪費(fèi)您的時(shí)間,不會(huì)帶來(lái)任何可度量的性能改進(jìn)。
foreach的復(fù)制行為比大多數(shù)人認(rèn)為的要復(fù)雜一些。通常情況下,“優(yōu)化”的版本會(huì)比原始版本慢。
foreach什么時(shí)候復(fù)制?
foreach是否復(fù)制數(shù)組以及復(fù)制的數(shù)量取決于三件事:
是否引用了迭代數(shù)組、它的refcount有多高以及迭代是否通過(guò)引用完成。
沒(méi)有引用,refcount == 1
在下面的代碼中,$array沒(méi)有被引用,并且refcount為1。在這種情況下,foreach不會(huì)復(fù)制數(shù)組(證明)——這與流行的觀(guān)點(diǎn)相反,即foreach總是復(fù)制沒(méi)有引用的迭代數(shù)組。
test(); function test() { $array = range(0, 100000); foreach ($array as $key => $value) { // ... } }
原因很簡(jiǎn)單:為什么要這樣做?foreach修改$array的唯一地方是它是內(nèi)部數(shù)組指針。這是預(yù)期的行為,因此不需要預(yù)防。
未引用,refcount > 1
下面的代碼看起來(lái)非常類(lèi)似于前面的代碼。唯一的區(qū)別是數(shù)組現(xiàn)在作為參數(shù)傳遞。這似乎是一個(gè)無(wú)關(guān)緊要的區(qū)別,但它確實(shí)改變了foreach的行為:
它現(xiàn)在將復(fù)制數(shù)組結(jié)構(gòu),而不是值(證明;如果你想知道這只是復(fù)制的結(jié)構(gòu),比較一下這個(gè)和那個(gè)腳本。第一個(gè)只復(fù)制結(jié)構(gòu),第二個(gè)兩個(gè)都復(fù)制)。
$array = range(0, 100000); test($array); function test($array) { foreach ($array as $key => $value) { // ... } }
乍一看這可能有點(diǎn)奇怪:
為什么當(dāng)數(shù)組通過(guò)參數(shù)傳遞時(shí),它會(huì)復(fù)制,但如果它是在函數(shù)中定義的,它就不會(huì)復(fù)制了?原因是數(shù)組zval現(xiàn)在在多個(gè)變量之間共享:函數(shù)外部的$array變量和函數(shù)內(nèi)部的$array變量。如果foreach在不復(fù)制數(shù)組結(jié)構(gòu)的情況下迭代數(shù)組,那么它不僅會(huì)改變函數(shù)中$array變量的數(shù)組指針,還會(huì)改變函數(shù)外$array變量的指針。因此foreach需要復(fù)制數(shù)組結(jié)構(gòu)(即散列表)。另一方面,這些值仍然可以共享zvals,因此不需要復(fù)制。
引用
下一種情況與前一種情況非常相似。唯一的區(qū)別是數(shù)組是通過(guò)引用傳遞的。在這種情況下,數(shù)組將不會(huì)被復(fù)制(證明)。
$array = range(0, 100000); test($array); function test(&$array) { foreach ($array as $key => $value) { // ... } }
在這種情況下,相同的推理適用于前一種情況:外部$數(shù)組和內(nèi)部$數(shù)組共享zvals。不同的是,它們現(xiàn)在是引用(isref == 1),因此在這種情況下,對(duì)內(nèi)部數(shù)組的任何更改都將對(duì)外部數(shù)組進(jìn)行。所以如果內(nèi)部數(shù)組的數(shù)組指針改變了,外部數(shù)組的數(shù)組指針也應(yīng)該改變。這就是foreach不需要復(fù)制的原因。
迭代通過(guò)引用
上面的例子都是按值迭代的。對(duì)于引用迭代,應(yīng)用相同的規(guī)則,但是附加值引用更改數(shù)組值的復(fù)制行為(關(guān)于結(jié)構(gòu)復(fù)制的行為保持不變)。
情況“未引用,refcount == 1”沒(méi)有改變。引用迭代意味著如果$值有任何變化,我們想要改變?cè)紨?shù)組,這樣數(shù)組就不會(huì)被復(fù)制(證明)。
“被引用”的情況也保持不變,在這種情況下,對(duì)$value的更改應(yīng)該會(huì)更改引用迭代數(shù)組的所有變量(證明)。
只有“未引用,refcount > 1”的情況發(fā)生了變化,因?yàn)楝F(xiàn)在需要復(fù)制數(shù)組結(jié)構(gòu)及其值。數(shù)組結(jié)構(gòu),因?yàn)榉駝t函數(shù)外部的$array變量的數(shù)組指針會(huì)改變,而對(duì)$value的改變也會(huì)改變外部的$array值(證明)。
總結(jié)
當(dāng)且僅當(dāng)?shù)鷶?shù)組未被引用且具有refcount > 1時(shí),foreach將復(fù)制數(shù)組結(jié)構(gòu)
foreach還將復(fù)制數(shù)組值,前提是且僅當(dāng)上一個(gè)點(diǎn)應(yīng)用并且迭代是通過(guò)引用完成時(shí)
相關(guān)文章
php實(shí)現(xiàn)XSS安全過(guò)濾的方法
這篇文章主要介紹了php實(shí)現(xiàn)XSS安全過(guò)濾的方法,實(shí)例分析了php針對(duì)XSS進(jìn)行安全過(guò)濾的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07swfupload 多文件上傳實(shí)現(xiàn)代碼
swfupload 采用flash+ajax方式上傳文件2008-08-08PHP將MySQL的查詢(xún)結(jié)果轉(zhuǎn)換為數(shù)組并用where拼接的示例
這篇文章主要介紹了PHP將MySQL的查詢(xún)結(jié)果轉(zhuǎn)換為數(shù)組并用where拼接的示例,這樣處理where條件時(shí)便可以在一定程度上優(yōu)化查詢(xún)和轉(zhuǎn)化的性能,需要的朋友可以參考下2016-05-05PHP基于phpqrcode生成帶LOGO圖像的二維碼實(shí)例
這篇文章主要介紹了PHP基于phpqrcode生成帶LOGO圖像的二維碼,可實(shí)現(xiàn)生成帶logo與不帶logo兩種二維碼的功能,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-07-07PHP大小寫(xiě)問(wèn)題:函數(shù)名和類(lèi)名不區(qū)分,變量名區(qū)分
這篇文章主要介紹了PHP大小寫(xiě)問(wèn)題,php中變量名是區(qū)分大小寫(xiě)的,而函數(shù)名與類(lèi)名是不區(qū)分的2013-06-06Yii中render和renderPartial的區(qū)別
這篇文章主要介紹了Yii中render和renderPartial的區(qū)別,以下由我們?cè)谛乓拙W(wǎng)絡(luò)公司開(kāi)發(fā)項(xiàng)目的時(shí)候終結(jié)出的一些經(jīng)驗(yàn)2014-09-09PHP Memcached應(yīng)用實(shí)現(xiàn)代碼
在很多場(chǎng)合,我們都會(huì)聽(tīng)到 memcached 這個(gè)名字,但很多同學(xué)只是聽(tīng)過(guò),并沒(méi)有用過(guò)或?qū)嶋H了解過(guò),只知道它是一個(gè)很不錯(cuò)的東東。這里簡(jiǎn)單介紹一下,memcached 是高效、快速的分布式內(nèi)存對(duì)象緩存系統(tǒng),主要用于加速 WEB 動(dòng)態(tài)應(yīng)用程序。2010-02-02php使用curl實(shí)現(xiàn)ftp文件下載功能
這篇文章主要為大家詳細(xì)介紹了php使用curl實(shí)現(xiàn)ftp文件下載功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05