Kuidas foreach silmus töötab. Tehke while ja foreach silmuseid. Võtme-väärtuse tsükkel

Foreach-konstruktsioon on selle variatsioon, mis sisaldub keeles, et hõlbustada massiivi elementide itereerimist. Foreach käsul on kaks versiooni, mis on mõeldud erinevat tüüpi massiivide jaoks:

foreach (massiivi $elemendina) (

foreach (massiivina $key => $element) (

Näiteks järgmise koodilõigu täitmisel:

$menüü = аrrау("pasta", "praad", "kartul", "kala", "friikartul");

foreach ($menu kui $item) (

printida "$item
";

väljastatakse järgmine tulemus:

Selles näites tuleb märkida kahte asja. Esiteks naaseb foreach-konstruktsioon automaatselt massiivi algusesse (teiste silmuskonstruktsioonide puhul seda ei juhtu). Teiseks pole vaja loendurit selgesõnaliselt suurendada või muul viisil massiivi järgmisele elemendile liikuda – see juhtub automaatselt iga foreachi iteratsiooniga.

Teist võimalust kasutatakse assotsiatiivsete massiividega töötamisel:

$wine_inventory = massiiv (

"merlot" => 15,

"zinfandel" => 17,

"sauvignon" => 32

foreach ($wine_inventory as $i => $item_count) (

print "$item_count pudelit $i-st jäänud
";

Sel juhul näeb tulemus välja selline:

15 pudelit merlot alles

17 pudelit tsinfandeli on alles

Jäänud on 32 pudelit sauvignoni

Nagu ülaltoodud näidetest näha, lihtsustab foreach-konstruktsioon massiividega töötamist oluliselt.

Lüliti konstruktsiooni tööpõhimõte meenutab mõneti if - avaldise hindamisel saadud tulemust võrreldakse potentsiaalsete vastete loendiga.

See on eriti kasulik mitme väärtuse kontrollimisel, kuna lüliti kasutamine muudab programmi visuaalsemaks ja kompaktsemaks. Switchi käsu üldine vorming on:

lüliti (avaldis) (

juhtum (seisukord):

juhtum (seisukord):

Testitav tingimus on märgitud lüliti märksõna järel sulgudes. Selle arvutuse tulemust võrreldakse järjestikku juhtumite osade tingimustega. Kui leitakse sobivus, käivitatakse vastava jaotise plokk. Kui vastet ei leita, käivitatakse valikuline vaikejaotise plokk.

Nagu näete hilisemates peatükkides, on PHP üks suurimaid tugevusi kasutaja sisendi käsitlemine. Oletame, et programm kuvab mitme valikuga ripploendi ja iga rida loendis vastab käsule, mis täidetakse eraldi juhtumikonstruktsioonis. Rakendust on väga mugav ehitada, kasutades käsku switch:

$user_input = "retseptid"; // Kasutaja valitud käsk

lüliti ($user_input) :

case("otsing"):

print "Teeme otsingu!";

case("sõnastik"):

print "Millist sõna tahaksite otsida?";

juhtum ("retseptid"):

print "Siin on retseptide nimekiri...";

print "Siin on menüü...";

Nagu ülaltoodud fragmendist näha, pakub switch käsk koodi selge ja visuaalse korralduse. Lülitustingimuses määratud muutujat (selles näites $user_input) võrreldakse kõigi järgnevate juhtumisektsioonide tingimustega. Kui juhtumiosas määratud väärtus ühtib võrreldava muutuja väärtusega, siis käivitatakse selle jaotise plokk. Katkestuskäsk takistab edasiste juhtumiosade kontrollimist ja lõpetab lüliti konstruktsiooni täitmise. Kui ükski kontrollitud tingimus ei ole täidetud, aktiveeritakse valikuline vaikejaotis. Kui vaikeosa puudub ja ükski tingimus ei ole tõene, siis lüliti käsk lihtsalt lõpeb ja programmi täitmine jätkub järgmise käsuga.

Peate meeles pidama, et kui juhtumiosas pole katkestuskäsku (vt järgmist jaotist), jätkub lüliti täitmine järgmise käsuga, kuni ilmneb katkestuskäsk või jõutakse lüliti käskluse lõpuni. Järgmine näide demonstreerib katkestuskäsu puudumise tagajärgi: $väärtus = 0,4;

lüliti ($väärtus) :

print "väärtus on 0,4
";

print "väärtus on 0,6
";

print "väärtus on 0,3
";

print "Sa ei valinud väärtust!";

Tulemus näeb välja selline:

Katkestuskäskluse puudumine tõi kaasa mitte ainult printimiskäskluse täitmise selles jaotises, kus vaste leiti, vaid ka järgmise jaotise printimiskäsku. Seejärel katkestati lülitilause käsud teisele printimiskäsule järgnenud lülituskäsuga.

Valik lüliti ja if-käskude vahel ei mõjuta programmi jõudlust praktiliselt. Otsus ühe või teise disaini kasutamise kohta on pigem programmeerija isiklik asi.

Käsk break katkestab kohe selle while, for või switchi täitmise, milles see leiti. Seda käsku mainiti juba eelmises jaotises, kuid vooluahela katkestamine ei ammenda katkestuskäsu võimalusi. Üldiselt näeb katkestuse süntaks välja järgmine:

Valikuline parameeter n määrab katkestuskäsuga lõpetatud juhtkonstruktsioonide tasemete arvu. Näiteks kui katkestuskäsk on pesastatud kahe, samas kui käskude vahele ja katkestusele järgneb number 2, väljuvad mõlemad tsüklid kohe. n vaikeväärtus on 1; Ühele tasemele väljumist saab näidata kas selgesõnalise 1 määramisega või parameetrita katkestuskäsu määramisega. Pange tähele, et käsk i f ei kuulu juhtkonstruktsioonide hulka, mida katkestuskäsk võib katkestada.

PHP foreach-tsüklit saab kasutada järgmiselt:

foreach($massiivi_nimi kui $väärtus)( //käivitatav kood)

foreach($massiivi_nimi kui $key =>$väärtus)( // //kood, mis tuleks käivitada)

Näide foreach-tsükli kasutamisest numbrimassiiviga

Selles näites loome viiest elemendist koosneva massiivi arvväärtustega. Seejärel kasutatakse selle massiivi itereerimiseks PHP foreach-silmust. Foreach-silmuse sees kasutasime massiivi väärtuste printimiseks kaja:

Vaadake demo ja koodi

Näide massiivivõtmete ja väärtustega

See näide kirjeldab teist viisi PHP foreach-tsükli kasutamiseks. Selleks lõime kolmest elemendist koosneva assotsiatiivse massiivi. See sisaldab töötajate nimesid ( võtmetena) ja töötasu suurus ( väärtustena):

Vaadake demo ja koodi

Näide massiivi elemendi väärtuse muutmisest foreach-tsüklis

Massiivi elementide väärtuste muutmiseks saate kasutada ka PHP massiivi foreach. Seda tehakse, kasutades väärtusmuutuja jaoks "&" enne "$". Näiteks:

&$väärtus_elemendi_väärtus

Väärtust muudetakse. Selle selgemaks muutmiseks vaadake järgmist näidet.

Selles näites lõime viiest elemendist koosneva arvulise massiivi. Pärast seda kasutasime elementide väärtuste kuvamiseks foreach-silmust.

Seejärel lõime teise foreach-tsükli, kus "& " lisatakse enne $ väärtus_elemendi_väärtus. Lokkis sulgudes määrame massiivi elementidele uued väärtused.

Et näha erinevust enne ja pärast uute väärtuste määramist, kuvatakse massiiv funktsiooni print_r() abil.

Vaadake demo ja koodi

Milleks PHP foreach-silmust kasutatakse?

Massiiviga töötamiseks kasutatakse PHP foreach-silmust. See kordub iga selle elemendi üle.

Massiividega töötamiseks võite kasutada ka for-tsüklit. Näiteks kasutades atribuuti pikkus massiivi pikkuse saamiseks ja seejärel rakendades seda maksimaalse operaatorina. Kuid foreach muudab selle lihtsamaks, kuna see on loodud töötama massiividega.

Kui töötate MySQL-iga, sobib see tsükkel selleks veelgi paremini. Näiteks saate andmebaasi tabelist valida mitu rida ja edastada need massiivi. Seejärel korrake foreach-silmust kasutades kõiki massiivi elemente ja tehke mõni toiming.

Pange tähele, et saate foreach-tsüklit kasutada massiivi või lihtsalt objektiga.

Foreach-silmuse kasutamine

PHP foreach-tsükli kasutamiseks on PHP-s kaks võimalust. Mõlemat kirjeldatakse allpool.

  • Esimese meetodi süntaks on:

foreach($massiivi_nimi kui $väärtus)( echo $value )

Sel juhul peate määrama massiivi nime ja seejärel muutuja $value.

Iga iteratsiooni puhul määratakse praeguse elemendi väärtus muutujale $value. Pärast iteratsiooni lõppu omistatakse muutujale järgmise elemendi väärtus. Ja nii edasi, kuni kõik massiivi elemendid on itereeritud.

  • Teise meetodi süntaks ( PHP foreach võtmeväärtusena):

See sobib assotsiatiivsetele massiividele, mis kasutavad võtme/väärtuse paare.

Iga iteratsiooni ajal määratakse praeguse elemendi väärtus muutujale $value_of_element. Lisaks on elemendi võti määratud muutujale $key_of_element.

Kui töötate numbrimassiividega, võite kasutada esimest meetodit, mis ei nõua elemendiklahve.

See väljaanne on tõlge artiklist " PHP foreach loop 2 võimalust selle kasutamiseks", mille valmistas ette sõbralik projektimeeskond

Hiljutisest PHP-i puudutavate huvitavate linkide kokkuvõttest leidsin lingi Nikita Popovi kommentaarile StackOverflow kohta, kus ta räägib üksikasjalikult foreach-juhtkonstruktsiooni kapoti all olevast mehhanismist.
Kuna foreach töötab mõnikord rohkem kui pisut kummalisel viisil, leidsin, et see vastus oli kasulik tõlkida.

Tähelepanu: see tekst eeldab põhiteadmisi zvalsi funktsionaalsusest PHP-s, eelkõige peaksite teadma, mis on refcount ja is_ref.
foreach töötab erinevat tüüpi olemitega: massiivide, lihtsate objektidega (kus saadaval olevad omadused on loetletud) ja läbitavate objektidega (õigemini objektidega, millel on määratletud sisemine get_iteratori käitleja). Peamiselt räägime siin massiividest, aga ülejäänutest räägin päris lõpus.

Enne alustamist paar sõna massiivide ja nende läbimise kohta, mis on konteksti mõistmiseks olulised.

Kuidas massiivi läbimine töötab?

Massiivid PHP-s on järjestatud räsitabelid (räsielemendid kombineeritakse topeltlingitud loendiks) ja foreach läbib massiivi määratud järjekorras.

PHP sisaldab kahte võimalust massiivi läbimiseks:

  • Esimene võimalus on sisemine massiivi osuti. See osuti on osa HashTable struktuurist ja on lihtsalt kursor praegusele räsitabeli elemendile. Sisemassiivi osutit saab karistamatult muuta, st kui praegune element kustutatakse, viiakse sisemine massiivi osuti järgmisele.
  • Teine iteratsioonimehhanism on väline massiivi osuti nimega HashPosition. See on sisuliselt sama mis sisemine massiivi osuti, kuid see ei ole räsitabeli osa. See väline iteratsiooniviis ei ole muutmiskindel. Kui eemaldate elemendi, millele HashPosition osutas, jääb teile rippuv osuti, mille tulemuseks on segmenteerimisviga.

Seega tuleks väliseid massiivi viiteid kasutada ainult siis, kui olete täiesti kindel, et läbimise ajal kasutajakoodi ei käivitata. Ja selline kood võib sattuda kõige ootamatumatesse kohtadesse, näiteks veakäsitlejasse või hävitajasse. Seetõttu peab PHP enamikul juhtudel kasutama sisemist kursorit välise asemel. Kui see oleks teisiti, võib PHP segmenteerimisveaga kokku kukkuda kohe, kui kasutaja hakkab midagi ebatavalist tegema.

Sisemise kursori probleem seisneb selles, et see on osa HashTable'ist. Nii et kui muudate seda, muutub HashTable koos sellega. Ja kuna PHP massiividele pääseb juurde väärtuse (ja mitte viite) alusel, peate massiivi kopeerima, et selle elemente läbida.

Lihtne näide, mis näitab kopeerimise tähtsust (muide, mitte nii haruldane), on pesastatud iteratsioon:

Foreach ($massiiv kui $a) ( foreach ($massiivi kui $b) ( // ... ) )

Siin soovite, et mõlemad silmused oleksid sõltumatud ja mitte ühe osutiga nutikalt ümber visatud.

Nii et me jõuame ette.

Massiivi läbimine foreachis

Nüüd teate, miks foreach peab massiivist enne selle läbimist koopia looma. Kuid see pole ilmselgelt kogu lugu. See, kas PHP teeb koopia või mitte, sõltub mitmest tegurist:

  • Kui itereeritav massiiv on viide, siis kopeerimist ei toimu, selle asemel käivitatakse addref:

    $ref =& $massiiv; // $massiivil on is_ref=1 nüüd foreach ($massiiv kui $val) ( // ... )
    Miks? Kuna kõik massiivi muudatused tuleb levitada viite abil, sealhulgas sisemine osuti. Kui foreach teeks sel juhul koopia, rikuks see lingi semantika.

  • Kui massiivi refcount=1, kopeerimist uuesti ei teostata. refcount=1 tähendab, et massiivi mujal ei kasutata ja foreach saab seda otse kasutada. Kui refcount on suurem kui üks, jagatakse massiivi teiste muutujatega ja muutmise vältimiseks peab foreach selle kopeerima (olenemata ülalkirjeldatud võrdlusjuhust).
  • Kui massiiv on viitega läbitud (foreach ($massiiv kui &$ref)), siis - olenemata kopeerimise või mittekopeerimise funktsioonist - saab massiivist viide.

Nii et see on mõistatuse esimene osa: kopeerimisfunktsioon. Teine osa on see, kuidas praegust iteratsiooni täidetakse, ja see on ka üsna kummaline. "Tavaline" iteratsioonimuster, mida te juba teate (ja mida PHP-s sageli kasutatakse – foreachist eraldi), näeb välja umbes selline (pseudokood):

Lähtesta(); while (hanki_praegused_andmed(&andmed) == EDU) ( code(); liigu_edasi(); )
iga iteratsioon näeb välja veidi erinev:

Lähtesta(); while (hanki_praegused_andmed(&andmed) == EDU) ( liigu_edasi(); kood(); )

Erinevus seisneb selles, et liigu_forward() käivitatakse tsükli alguses, mitte lõpus. Seega, kui kasutajakood kasutab elementi $i, osutab sisemine massiivi osuti juba elemendile $i+1.

See foreachi töörežiim on ka põhjus, miks sisemine massiivi kursor liigub praeguse kustutamise korral järgmisele elemendile, mitte eelmisele (nagu võite eeldada). Kõik on loodud foreachiga suurepäraselt töötama (kuid ilmselgelt ei tööta see kõige muuga sama hästi, jättes elemendid vahele).

Koodi tagajärjed

Ülaltoodud käitumise esimene tagajärg on see, et foreach kopeerib itereeritava massiivi paljudel juhtudel (aeglaselt). Kuid ärge kartke: proovisin eemaldada kopeerimisnõude ja ei näinud kiirust mujal, välja arvatud kunstlikes võrdlusnäitajates (mis kordus kaks korda kiiremini). Tundub, et inimesed lihtsalt ei itereeri piisavalt.

Teine tagajärg on see, et tavaliselt ei tohiks olla muid tagajärgi. Foreachi käitumine on kasutajale üldiselt üsna arusaadav ja töötab lihtsalt nii nagu peab. Teid ei tohiks huvitada, kuidas kopeerimine toimub (või kas see üldse toimub) või millisel konkreetsel ajahetkel kursorit liigutatakse.

Ja kolmas tagajärg – ja siit jõuamegi teie probleemini – on see, et mõnikord näeme väga kummalist käitumist, millest on raske aru saada. See juhtub konkreetselt siis, kui proovite muuta massiivi ennast, mida te tsüklina läbite.

PHP testidest leiate suure hulga servajuhtumite käitumist, mis ilmnevad massiivi muutmisel iteratsiooni ajal. Võite alustada selle testiga, seejärel muuta aadressis 012 013-ks ja nii edasi. Näete, kuidas foreach käitumine erinevates olukordades avaldub (kõikvõimalikud linkide kombinatsioonid jne).

Nüüd pöördume tagasi teie näidete juurde:

Foreach ($massiiv kui $üksus) ( kaja "$item\n"; $massiiv = $item; ) print_r($massiiv); /* Väljund tsüklis: 1 2 3 4 5 $massiiv pärast tsüklit: 1 2 3 4 5 1 2 3 4 5 */

Siin on $massiivil enne tsüklit refcount=1, nii et seda ei kopeerita, vaid saab aadressi. Kui määrate väärtuse $massiivile, jagatakse zval pooleks, nii et massiiv, millele elemente lisate, ja massiiv, mida itereerite, on kaks erinevat massiivi.

Foreach ($massiiv kui $key => $üksus) ( $massiiv[$key + 1] = $item + 2; kaja "$item\n"; ) print_r($massiivi); /* Väljund tsüklis: 1 2 3 4 5 $massiiv pärast tsüklit: 1 3 4 5 6 7 */

Sama olukord, mis esimeses testis.

// Nihutage kursorit ühe võrra, et veenduda, et see ei mõjuta foreachi var_dump(each($array)); foreach ($massiiv kui $üksus) ( echo "$item\n"; ) var_dump(each($array)); /* Väljundmassiiv(4) ( => int(1) ["väärtus"]=> int(1) => int(0) ["võti"]=> int(0) ) 1 2 3 4 5 bool( vale) */

Jälle sama lugu. Foreach-tsükli ajal on teil refcount=1 ja saate ainult aadressi aadressi, sisemist $massiivi osutit muudetakse. Silmuse lõpus muutub kursor NULL-iks (see tähendab, et iteratsioon on lõpetatud). igaüks demonstreerib seda, tagastades vale.

Foreach ($massiiv kui $key => $item) ( kaja "$item\n"; every($array); ) /* Väljund: 1 2 3 4 5 */

Foreach ($massiiv kui $key => $item) ( kaja "$item\n"; reset($array); ) /* Väljund: 1 2 3 4 5 */

Kuid need näited ei ole piisavalt veenvad. Käitumine hakkab muutuma väga ettearvamatuks, kui kasutate vooluahelas:

Foreach ($massiiv kui $val) ( var_dump(current($array)); ) /* Väljund: 2 2 2 2 2 */

Siinkohal tuleb meeles pidada, et voolule pääseb ligi ka viitega, hoolimata sellest, et massiivi ei muudeta. Seda on vaja järjepidevaks töötamiseks kõigi teiste funktsioonidega, näiteks järgmisega, millele on juurdepääs viitega (praegune on tegelikult eelistatav ref-funktsioon; see võib saada väärtuse, kuid kasutab viidet, kui see on võimalik). Viide tähendab, et massiiv tuleb eraldada, nii et $massiivi ja $massiivi koopia, mida foreach kasutab, on sõltumatud. Miks sa saad 2, mitte 1, on ka eespool mainitud: foreach suurendab massiivi osutit enne kasutajakoodi algust, mitte pärast. Nii et isegi kui kood töötab endiselt esimese elemendiga, on foreach kursori juba teisele viinud.

Proovime nüüd väikest muudatust:

$ref = &$massiiv; foreach ($massiiv kui $val) ( var_dump(current($array)); ) /* Väljund: 2 3 4 5 false */

Siin on is_ref=1, nii et massiivi ei kopeerita (sama, mis ülal). Kuid nüüd, kus on is_ref, ei pea massiivi enam poolitama, voolule viidates. Nüüd töötavad praegune ja foreach sama massiiviga. Näete massiivi ühe võrra nihutatud just seetõttu, kuidas foreach kursorit kohtleb.

Näete sama asja, kui läbite massiivi viite abil:

Foreach ($massiiv kui &$val) ( var_dump(current($array)); ) /* Väljund: 2 3 4 5 false */

Siin on oluline see, et foreach määrab meie $massiivi is_ref=1, kui ta sellest viitena üle liigub, nii et see on sama, mis ülal.

Veel üks väike variatsioon, siin määrame oma massiivi teisele muutujale:

$foo = $massiiv; foreach ($massiiv kui $val) ( var_dump(current($array)); ) /* Väljund: 1 1 1 1 1 */

Siin on $massiivi kordusloenduseks tsükli käivitamisel 2, seega tuleb enne alustamist koopia teha. Seega on $massiivi ja foreachi kasutatav massiiv algusest peale erinevad. Seetõttu saate sisemise massiivi osuti asukoha, mis oli asjakohane enne tsükli algust (antud juhul oli see esimesel positsioonil).

Objektide iteratsioon

Objektide itereerimisel on mõttekas kaaluda kahte juhtumit:

Objekt ei ole läbitav (või õigemini, sisemine get_iteratori töötleja pole määratletud)

Sel juhul toimub iteratsioon peaaegu samamoodi nagu massiivide puhul. Sama kopeerimise semantika. Ainus erinevus on see, et foreach käivitab lisakoodi, et jätta vahele atribuudid, mis pole praeguses ulatuses saadaval. Paar huvitavat fakti veel:

  • Deklareeritud atribuutide puhul optimeerib PHP atribuutide räsitabeli uuesti. Kui te objekti itereerite, peab see selle räsitabeli rekonstrueerima (mis suurendab mälukasutust). Mitte, et peaksite selle pärast muretsema, lihtsalt olge teadlik.
  • Igal iteratsioonil hangitakse uuesti atribuutide räsitabel, mis tähendab, et PHP kutsub ikka ja jälle välja get_properties. “Tavaliste” atribuutide puhul pole see nii oluline, kuid kui atribuudid luuakse dünaamiliselt (seda teevad sageli sisseehitatud klassid), siis atribuutide tabel arvutatakse iga kord uuesti.
Läbitav objekt

Sel juhul ei kehti kõik ülalöeldud. Samuti ei kopeeri PHP ega kasuta enne silmuse loomist mingeid nippe, näiteks kursorit. Arvan, et läbitava objekti läbimise viis on palju etteaimatavam ega vaja täiendavat kirjeldamist.

Itereeritava asendamine tsükli ajal

Teine ebatavaline juhtum, mida ma ei maininud, on see, et PHP võimaldab tsükli ajal itereeritavat asendada. Võite alustada ühe massiiviga ja jätkata, asendades selle poole peal teisega. Või alustage massiiviga, seejärel asendage see objektiga:

$arr = ; $obj = (objekt) ; $ref =& $arr; foreach ($ref as $val) ( kaja "$val\n"; if ($val == 3) ( $ref = $obj; ) ) /* Väljund: 1 2 3 6 7 8 9 10 */

Nagu näete, alustas PHP lihtsalt teise olemi läbimist niipea, kui asendamine toimus.

Sisemise massiivi osuti muutmine iteratsiooni ajal

Üks viimane detail foreach käitumisest, mida ma ei maininud (sest seda saab kasutada tõesti imelik käitumine): mis võib juhtuda, kui proovite tsükli ajal sisemist massiivi kursorit muuta.

Siin ei pruugi te saada seda, mida ootasite: kui helistate tsükli põhiosas next või prev (viitega möödumise korral), näete, et sisemine osuti on liikunud, kuid see ei mõjuta tsükli käitumist. iteraator. Põhjus on selles, et foreach teeb pärast iga tsükli läbimist varukoopia HashPointeri praeguse elemendi praegusest asukohast ja räsi. Järgmisel käigul kontrollib foreach, kas sisemise osuti asukoht on muutunud, ja proovib seda selle räsi abil taastada.

Vaatame, mida tähendab "proovin". Esimene näide näitab, kuidas sisemise kursori muutmine ei muuda foreach-režiimi:

$massiivi = ; $ref =& $massiiv; foreach ($massiiv kui $väärtus) ( var_dump($value); reset($array); ) // väljund: 1, 2, 3, 4, 5

Proovime nüüd tühistada elemendi, millele foreach esimesel läbimisel juurde pääseb (1. klahv):

$massiivi = ; $ref =& $massiiv; foreach ($massiiv kui $väärtus) ( var_dump($value); unset($array); reset($array); ) // väljund: 1, 1, 3, 4, 5

Siin näete, et loendur on lähtestatud, kuna sobiva räsiga elementi ei leitud.

Pidage meeles, et räsi on lihtsalt räsi. Kokkupõrkeid juhtub. Proovime nüüd seda:

$massiiv = ["Ez Ez" => 1, "EzFY" => 2, "FYEz" => 3]; $ref =& $massiiv; foreach ($massiiv kui $väärtus) ( unset($array["EzFY"]); $array["FYFZ"] = 4; reset($array); var_dump($value); ) // väljund: 1 1 3 4

Töötab nii nagu ootasime. Eemaldasime EzFY võtme (see, kus foreach asus), seega tehti lähtestamine. Lisasime ka lisavõtme, nii et näeme lõpus 4.

Ja siit tuleb tundmatu. Mis juhtub, kui asendate võtme FYFY võtmega FYFZ? Proovime:

$massiiv = ["Ez Ez" => 1, "EzFY" => 2, "FYEz" => 3]; $ref =& $massiiv; foreach ($massiiv kui $väärtus) ( unset($array["EzFY"]); $array["FYFY"] = 4; reset($array); var_dump($value); ) // väljund: 1 4

Nüüd on silmus liikunud otse uue elemendi juurde, jättes kõik muu vahele. Seda seetõttu, et FYFY-klahvil on kokkupõrge EzFY-ga (tegelikult ka kõik selle massiivi võtmed). Lisaks asub FYFY element samal mäluaadressil kui äsja kustutatud EzFY element. Nii et PHP puhul on see sama positsioon sama räsiga. Positsioon "taastati" ja toimub üleminek massiivi lõppu.

Sageli peate läbima PHP massiivi kõik elemendid ja tegema iga elemendiga mõne toimingu. Näiteks saate iga väärtuse väljastada HTML-i tabelisse või anda igale elemendile uue väärtuse.

Selles õppetükis vaatleme foreach-konstruktsiooni, kui korraldate tsüklit indekseeritud ja seotud massiivide üle.

Elementide väärtuste silmus

Foreachi lihtsaim kasutusjuht on väärtuste silmus läbi indekseeritud massiivi. Põhiline süntaks:

Foreach ($massiiv kui $value) (// Tehke midagi $value-ga ) // Siin käivitatakse kood pärast tsükli lõppemist

Näiteks järgmine skript kordab indekseeritud massiivi direktorite loendit ja prindib välja igaühe nimed:

$direktorid = array("Alfred Hitchcock", "Stanley Kubrick", "Martin Scorsese", "Fritz Lang"); foreach ($directors kui $director) ( echo $director . "
"; }

Ülaltoodud kood väljastab:

Alfred Hitchcock Stanley Kubrick Martin Scorsese Fritz Lang

Sirvige võtmeid ja väärtusi

Aga seotud massiivid? Seda tüüpi massiivi kasutamisel peab teil sageli olema juurdepääs iga elemendi võtmele ja selle väärtusele. Foreach-konstruktsioonil on viis probleemi lahendamiseks:

Foreach ($massiiv kui $key => $value) (// Tehke midagi $key ja/või $value abil) // Siin käivitatakse kood pärast tsükli lõppemist

Näide tsükli korraldamisest seotud massiivi kaudu, mis sisaldab teavet filmide kohta, kuvades iga elemendi võtme ja selle väärtuse HTML-i definitsioonide loendis:

$movie = array("title" => "Tagaaken", "režissöör" => "Alfred Hitchcock", "aasta" => 1954, "minutit" => 112); kaja"

"; foreach ($movie as $key => $value) (kaja "
$key:
"; kaja"
$ väärtus
"; ) kaja"
";

Käivitamisel väljastab see skript:

Pealkiri: Tagaakna režissöör: Alfred Hitchcock aasta: 1954 minutit: 112

Elemendi väärtuse muutmine

Kuidas on lood elemendi väärtuse muutmisega tsükli läbimisel? Võite proovida seda koodi:

Foreach ($myArray kui $väärtus) ($value = 123; )

Kui aga seda käivitate, leiate, et massiivi väärtused ära muutu. Põhjus on selles, et foreach töötab koopia massiivi väärtused, mitte originaaliga. Nii jääb algne massiiv puutumatuks.

Massiivi väärtuste muutmiseks vajate link tähendusele. Selleks peate foreach-konstruktsioonis väärtusmuutuja ette panema & märgi:

Foreach ($myArray kui &$value) ($value = 123; )

Näiteks järgmine skript liigub massiivi $directors iga elemendi (režissööri nime) läbi ning kasutab ees- ja perekonnanime vahetamiseks funktsiooni PHP explode() ja loendikonstruktsiooni:

$direktorid = array("Alfred Hitchcock", "Stanley Kubrick", "Martin Scorsese", "Fritz Lang"); // Muutke iga elemendi nimevormingut foreach ($directors kui &$director) ( list($firstName, $lastName) = explode(" ", $director); $director = "$lastName, $firstName"; ) unset ( $direktor); // Trüki lõpptulemus foreach ($directors kui $director) ( echo $director . "
"; }

Skript väljastab:

Hitchcock, Alfred Kubrick, Stanley Scorsese, Martin Lang, Fritz

Pange tähele, et skript kutsub pärast esimese tsükli lõppemist välja muutuja $director eemaldamiseks funktsiooni unset(). See on hea tava, kui kavatsete muutujat hiljem skriptis teises kontekstis kasutada.

Kui te viidet ei eemalda, on oht, et kui jätkate muutuja $director kasutamist, käivitate koodi, mis viitab kogemata massiivi viimasele elemendile ("Lang, Fritz"), mis toob kaasa soovimatuid tagajärgi!

Kokkuvõte

Selles õpetuses vaatlesime, kuidas kasutada PHP foreach konstruktsiooni massiivi elementide läbimiseks. Arutati järgmisi küsimusi:

  • Kuidas massiivi elemente läbida
  • Kuidas pääseda juurde iga elemendi võtmele ja väärtusele
  • Kuidas kasutada tsüklit läbides väärtuste muutmiseks viidet

Kujutage ette, et teil on assotsiatiivne massiiv, mida soovite korrata. PHP pakub lihtsat viisi massiivi iga elemendi kordamööda kasutamiseks Foreachi konstruktsiooni abil.

Lihtsas keeles kõlaks see umbes nii:
"Käivitage see kood määratud massiivi iga elemendi jaoks."

Kuigi see jätkub seni, kuni mõni tingimus on täidetud, jätkub foreach-tsükkel seni, kuni see on läbinud massiivi kõik elemendid.

PHP Foreach: näide

Meil on assotsiatiivne massiiv, mis salvestab meie ettevõtte inimeste nimed ja nende vanused. Tahame teada, kui vana iga töötaja on, seega kasutame kõigi nimede ja vanuse printimiseks iga jaoks mõeldud silmust.

$töötajaVanused; $töötajaAges["Lisa"] = "28"; $töötajaAges["Jack"] = "16"; $töötajaAges["Ryan"] = "35"; $töötajaAges["Rachel"] = "46"; $töötajaAges["Grace"] = "34"; foreach($employeeAges as $key => $value)( echo "Nimi: $key, Vanus: $value
"; }

Saame tulemuse:

Nimi: Lisa, Vanus: 28 Nimi: Jack, Vanus: 16 Nimi: Ryan, Vanus: 35 Nimi: Rachel, Vanus: 46 Nimi: Grace, Vanus: 34

Noh, tulemus on hea ja arusaadav, aga foreach konstruktsiooni süntaks pole kuigi lihtne ja arusaadav. Vaatame seda lähemalt.

Iga süntaksi jaoks: $midagi kui $key => $väärtus

Kogu see hullumeelsus tähendab umbkaudu: "Assotsiatiivse massiivi $ töötajaAges iga elemendi jaoks tahan ma pääseda $keyle ja selle sees olevale väärtusele, st $väärtusele.

Operaator "=>" tähistab võtme ja väärtuse vahelist suhet. Meie näites nimetasime need võtmeks - $võti ja väärtuseks - $väärtus. Lihtsam oleks neid aga pidada nimeks ja vanuseks. Allpool oma näites teeme seda ja pange tähele, et tulemus on sama, kuna muutsime ainult võtmete ja väärtustega seotud muutujate nimesid.

$töötajaVanused; $töötajaAges["Lisa"] = "28"; $töötajaAges["Jack"] = "16"; $töötajaAges["Ryan"] = "35"; $töötajaAges["Rachel"] = "46"; $töötajaAges["Grace"] = "34"; foreach($töötajaVanused kui $nimi => $vanus)( echo "Nimi: $nimi, vanus: $vanus
"; }

Noh, tulemus, kordame, on sama.