Hoe de foreach-lus werkt. Voer while- en foreach-lussen uit. Sleutel-waarde-lus

De foreach-constructie is een variatie hierop die in de taal is opgenomen om het herhalen van de elementen van een array eenvoudiger te maken. Er zijn twee versies van de foreach-opdracht, ontworpen voor verschillende typen arrays:

foreach (array als $element) (

foreach (array als $key => $element) (

Bijvoorbeeld bij het uitvoeren van het volgende fragment:

$menu = аrrау("pasta", "biefstuk", "aardappelen", "vis", "friet");

foreach ($menu als $item) (

print "$item
";

het volgende resultaat wordt uitgevoerd:

Er zijn twee dingen waar we op moeten letten in dit voorbeeld. Ten eerste keert de foreach-constructie automatisch terug naar het begin van de array (dit gebeurt niet bij andere lusconstructies). Ten tweede is het niet nodig om de teller expliciet te verhogen of anderszins naar het volgende element van de array te gaan; dit gebeurt automatisch bij elke iteratie van de foreach.

De tweede optie wordt gebruikt bij het werken met associatieve arrays:

$wine_inventory = array (

"merlot" => 15,

"zinfandel" => 17,

"sauvignon" => 32

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

print "$item_count flessen van $i resterend
";

In dit geval ziet het resultaat er als volgt uit:

Er zijn nog 15 flessen merlot over

Er zijn nog 17 flessen zinfandel over

Er zijn nog 32 flessen sauvignon over

Zoals je uit de bovenstaande voorbeelden kunt zien, vereenvoudigt de foreach-constructie het werken met arrays aanzienlijk.

Het werkingsprincipe van de switch-constructie doet enigszins denken aan if - het resultaat dat wordt verkregen door het evalueren van de expressie wordt gecontroleerd aan de hand van een lijst met mogelijke overeenkomsten.

Dit is vooral handig bij het controleren van meerdere waarden, omdat het gebruik van een schakelaar het programma visueler en compacter maakt. Het algemene formaat van het schakelcommando is:

schakelaar (uitdrukking) (

geval (conditie):

geval (conditie):

De conditie die wordt getest, wordt tussen haakjes aangegeven na het sleutelwoord switch. Het resultaat van de berekening wordt sequentieel vergeleken met de omstandigheden in de casussecties. Als er een match wordt gevonden, wordt het blok van de bijbehorende sectie uitgevoerd. Als er geen overeenkomst wordt gevonden, wordt het optionele standaardsectieblok uitgevoerd.

Zoals je in latere hoofdstukken zult zien, is een van de grootste sterke punten van PHP de omgang met gebruikersinvoer. Laten we zeggen dat een programma een vervolgkeuzelijst weergeeft met verschillende opties, en elke regel in de lijst komt overeen met een opdracht die wordt uitgevoerd in een afzonderlijke case-constructie. Het is erg handig om de implementatie te bouwen met behulp van het switch-commando:

$user_input = "recepten"; // Door de gebruiker geselecteerde opdracht

schakelaar ($user_input):

case("zoeken") :

print "Laten we een zoekopdracht uitvoeren!";

case("woordenboek") :

print "Welk woord wil je opzoeken?";

case("recepten") :

print "Hier is een lijst met recepten...";

afdrukken "Hier is het menu...";

Zoals je uit het bovenstaande fragment kunt zien, zorgt het schakelcommando voor een duidelijke en visuele organisatie van de code. De variabele die is opgegeven in de schakelvoorwaarde (in dit voorbeeld $user_input) wordt vergeleken met de voorwaarden van alle volgende casussecties. Als de waarde die is opgegeven in de case-sectie overeenkomt met de waarde van de variabele die wordt vergeleken, wordt het blok van deze sectie uitgevoerd. Het break-commando voorkomt dat verdere casussecties worden gecontroleerd en beëindigt de uitvoering van de switch-constructie. Als aan geen van de aangevinkte voorwaarden wordt voldaan, wordt de optionele standaardsectie geactiveerd. Als er geen standaardsectie is en geen van de voorwaarden waar is, eindigt het schakelcommando eenvoudigweg en gaat de programma-uitvoering verder met het volgende commando.

U moet niet vergeten dat als er geen break-commando in de case-sectie staat (zie de volgende sectie), de uitvoering van de switch doorgaat met het volgende commando totdat een break-commando wordt tegengekomen of het einde van de switch-instructie is bereikt. Het volgende voorbeeld demonstreert de gevolgen van het missen van een break-opdracht: $value = 0,4;

schakelaar($waarde) :

afdrukken "waarde is 0,4
";

afdrukken "waarde is 0,6
";

afdrukken "waarde is 0,3
";

print "Je hebt geen waarde gekozen!";

Het resultaat ziet er als volgt uit:

Het ontbreken van een break-commando resulteerde in de uitvoering van niet alleen het printcommando in de sectie waar de match werd gevonden, maar ook het printcommando in de volgende sectie. Vervolgens werden de commando's in de switch-instructie onderbroken door een switch-commando dat volgde op het tweede printcommando.

De keuze tussen de switch- en if-opdrachten heeft vrijwel geen invloed op de prestaties van het programma. De beslissing om het ene of het andere ontwerp te gebruiken is eerder een persoonlijke zaak voor de programmeur.

Het break-commando verbreekt onmiddellijk de uitvoering van de while-, for- of switch-instructie waarin deze wordt aangetroffen. Dit commando werd al genoemd in de vorige sectie, maar het onderbreken van de huidige lus put niet uit de mogelijkheden van het break-commando. Over het algemeen ziet de break-syntaxis er als volgt uit:

De optionele parameter n specificeert het aantal niveaus van besturingsconstructies dat wordt beëindigd door het break-commando. Als een break-commando bijvoorbeeld binnen twee while-commando's is genest en de break wordt gevolgd door het getal 2, worden beide lussen onmiddellijk afgesloten. De standaardwaarde voor n is 1; het verlaten van één niveau kan worden aangegeven door expliciet 1 op te geven of door het break-commando zonder parameter op te geven. Merk op dat het if-commando niet een van de besturingsconstructies is die kunnen worden onderbroken door het break-commando.

De PHP foreach-lus kan als volgt worden gebruikt:

foreach($array_name as $value)(//uit te voeren code)

foreach($array_name as $key =>$value)( // //code die moet worden uitgevoerd)

Voorbeeld van het gebruik van een foreach-lus met een numerieke array

In dit voorbeeld maken we een array van vijf elementen met numerieke waarden. De PHP foreach-lus wordt vervolgens gebruikt om door deze array te itereren. Binnen de foreach-lus hebben we echo gebruikt om de arraywaarden af ​​te drukken:

Bekijk demo en code

Voorbeeld met arraysleutels en waarden

Dit voorbeeld beschrijft een andere manier om de PHP foreach-lus te gebruiken. Om dit te doen, hebben we een associatieve array van drie elementen gemaakt. Het bevat de namen van werknemers ( als sleutels) en de hoogte van het loon ( als waarden):

Bekijk demo en code

Een voorbeeld van het wijzigen van de waarde van een array-element in een foreach-lus

Je kunt ook PHP array foreach gebruiken om de waarden van array-elementen te wijzigen. Dit wordt gedaan door "&" vóór "$" te gebruiken voor de waardevariabele. Bijvoorbeeld:

&$waarde_van_element

De waarde wordt gewijzigd. Om het duidelijker te maken, overweeg het volgende voorbeeld.

In dit voorbeeld hebben we een numerieke array van vijf elementen gemaakt. Daarna hebben we een foreach-lus gebruikt om de waarden van de elementen weer te geven.

Vervolgens hebben we nog een foreach-lus gemaakt, waarbij "& " wordt toegevoegd vóór $value_of_element. Binnen de accolades kennen we nieuwe waarden toe aan de elementen van de array.

Om het verschil voor en na het toekennen van nieuwe waarden te zien, wordt de array weergegeven met behulp van de print_r() functie.

Bekijk demo en code

Waar wordt de PHP foreach-lus voor gebruikt?

De PHP foreach-lus wordt gebruikt om met een array te werken. Het herhaalt zich over elk van zijn elementen.

U kunt ook een for-lus gebruiken om met arrays te werken. Gebruik bijvoorbeeld de eigenschap length om de lengte van een array op te halen en deze vervolgens toe te passen als de operator max. Maar foreach maakt het eenvoudiger omdat het is ontworpen om met arrays te werken.

Werk je met MySQL, dan is deze cyclus daarvoor nog geschikter. U kunt bijvoorbeeld meerdere rijen uit een databasetabel selecteren en deze in een array doorgeven. Daarna itereert u met behulp van een foreach-lus alle elementen van de array en voert u een actie uit.

Merk op dat u een foreach-lus kunt gebruiken met een array of alleen met een object.

Een foreach-lus gebruiken

Er zijn twee manieren om de PHP foreach-lus in PHP te gebruiken. Beide worden hieronder beschreven.

  • De syntaxis voor de eerste methode is:

foreach($array_name als $waarde)( echo $waarde )

In dit geval moet u de arraynaam opgeven en vervolgens de variabele $value.

Voor elke iteratie wordt de waarde van het huidige element toegewezen aan de variabele $value. Nadat de iteratie is voltooid, krijgt de variabele de waarde van het volgende element toegewezen. En zo verder totdat alle elementen van de array zijn herhaald.

  • Syntaxis van de tweede methode ( PHP foreach als sleutelwaarde):

Dit is geschikt voor associatieve arrays die sleutel/waarde-paren gebruiken.

Tijdens elke iteratie wordt de waarde van het huidige element toegewezen aan de variabele $value_of_element. Bovendien wordt de elementsleutel toegewezen aan de variabele $key_of_element.

Als u met numerieke arrays werkt, kunt u de eerste methode gebruiken, waarvoor geen elementsleutels nodig zijn.

Deze publicatie is een vertaling van het artikel “ PHP foreach loop 2 manieren om het te gebruiken", opgesteld door het vriendelijke projectteam

In een recente samenvatting van interessante links over PHP vond ik een link naar een commentaar van Nikita Popov op StackOverflow, waar hij in detail vertelt over het mechanisme “onder de motorkap” van de foreach-besturingsconstructie.
Omdat foreach soms op meer dan een beetje vreemde manieren werkt, dacht ik dat het nuttig zou zijn om dit antwoord te vertalen.

Let op: deze tekst veronderstelt een basiskennis van de functionaliteit van zvals in PHP, in het bijzonder moet je weten wat refcount en is_ref zijn.
foreach werkt met entiteiten van verschillende typen: met arrays, met eenvoudige objecten (waar de beschikbare eigenschappen worden vermeld) en met Traversable-objecten (of beter gezegd, objecten waarvoor een interne get_iterator-handler is gedefinieerd). We hebben het hier vooral over arrays, maar ik zal het helemaal aan het einde over de rest hebben.

Voordat we beginnen, een paar woorden over arrays en hun verplaatsing, belangrijk voor het begrijpen van de context.

Hoe werkt array-traversal?

Arrays in PHP zijn geordende hashtabellen (hashelementen worden gecombineerd in een dubbel gekoppelde lijst) en foreach doorloopt de array in de opgegeven volgorde.

PHP bevat twee manieren om een ​​array te doorkruisen:

  • De eerste manier is een interne array-pointer. Deze pointer maakt deel uit van de HashTable-structuur en is eenvoudigweg een pointer naar het huidige hashtabelelement. De interne array-pointer kan ongestraft worden gewijzigd, dat wil zeggen dat als het huidige element wordt verwijderd, de interne array-pointer naar het volgende wordt verplaatst.
  • Het tweede iteratiemechanisme is een externe array-aanwijzer genaamd HashPosition. Dit is in wezen hetzelfde als een interne array-aanwijzer, maar maakt geen deel uit van de HashTable. Deze externe manier van iteratie is niet veranderingsveilig. Als u het element verwijdert waarnaar HashPosition verwijst, blijft er een bungelende aanwijzer over, wat zal resulteren in een segmentatiefout.

Externe array-pointers mogen dus alleen worden gebruikt als u er absoluut zeker van bent dat er tijdens de traversal geen gebruikerscode wordt uitgevoerd. En dergelijke code kan op de meest onverwachte plaatsen terechtkomen, zoals een foutafhandelaar of een destructor. Dit is de reden waarom PHP in de meeste gevallen een interne pointer moet gebruiken in plaats van een externe. Anders zou PHP kunnen crashen met een segmentatiefout zodra de gebruiker iets ongewoons begint te doen.

Het probleem met de interne pointer is dat deze deel uitmaakt van de HashTable. Dus als u deze wijzigt, verandert de HashTable mee. En aangezien arrays in PHP toegankelijk zijn op basis van waarde (en niet op basis van referentie), bent u gedwongen de array te kopiëren om de elementen ervan te doorlopen.

Een eenvoudig voorbeeld dat het belang van kopiëren laat zien (niet zo ongewoon trouwens) is geneste iteratie:

Foreach ($array als $a) ( foreach ($array als $b) ( // ... ) )

Hier wil je dat beide lussen onafhankelijk zijn en niet slim rondgegooid worden met één aanwijzer.

Dus we komen naar voren.

Een array in foreach doorlopen

Nu weet u waarom foreach een kopie van de array moet maken voordat deze wordt doorlopen. Maar dit is duidelijk niet het hele verhaal. Of PHP een kopie maakt of niet, hangt van verschillende factoren af:

  • Als de iterabele array een referentie is, zal er niet worden gekopieerd, maar zal addref worden uitgevoerd:

    $ref =& $matrix; // $array heeft is_ref=1 nu foreach ($array as $val) ( // ... )
    Waarom? Omdat elke wijziging aan de array moet worden doorgegeven door middel van referentie, inclusief de interne pointer. Als foreach in dit geval een kopie zou maken, zou dit de semantiek van de link verbreken.

  • Als de array refcount=1 heeft, wordt het kopiëren opnieuw niet uitgevoerd. refcount=1 betekent dat de array niet elders wordt gebruikt en dat foreach deze direct kan gebruiken. Als refcount groter is dan één, wordt de array gedeeld met andere variabelen en om wijziging te voorkomen moet foreach deze kopiëren (ongeacht het hierboven beschreven referentiegeval).
  • Als de array door referentie wordt doorlopen (foreach ($array as &$ref)), dan wordt de array - ongeacht de kopieer- of niet-kopieerfunctie - een referentie.

Dit is dus het eerste deel van het mysterie: de kopieerfunctie. Het tweede deel gaat over hoe de huidige iteratie wordt uitgevoerd, en het is ook behoorlijk vreemd. Het "normale" iteratiepatroon dat je al kent (en dat vaak wordt gebruikt in PHP - los van foreach) ziet er ongeveer zo uit (pseudocode):

Opnieuw instellen(); while (get_current_data(&data) == SUCCES) ( code(); move_forward(); )
de foreach-iteratie ziet er een beetje anders uit:

Opnieuw instellen(); while (get_current_data(&data) == SUCCES) ( move_forward(); code(); )

Het verschil is dat move_forward() aan het begin wordt uitgevoerd in plaats van aan het einde van de lus. Wanneer de gebruikerscode dus element $i gebruikt, wijst de interne array-aanwijzer al naar element $i+1.

Deze werkingsmodus van foreach is ook de reden waarom de interne array-aanwijzer naar het volgende element gaat als het huidige wordt verwijderd, in plaats van naar het vorige (zoals je zou verwachten). Alles is ontworpen om prima met foreach te werken (maar zal uiteraard niet zo goed werken met al het andere, waarbij elementen worden overgeslagen).

Code-implicaties

Het eerste gevolg van het bovenstaande gedrag is dat foreach de iterabele array in veel gevallen (langzaam) kopieert. Maar wees niet bang: ik heb geprobeerd de kopieervereiste te verwijderen en kon nergens enige versnelling zien, behalve in de kunstmatige benchmarks (die tweemaal zo snel herhaalden). Het lijkt erop dat mensen gewoon niet genoeg herhalen.

De tweede consequentie is dat er normaal gesproken geen andere gevolgen mogen zijn. Het gedrag van foreach is over het algemeen heel begrijpelijk voor de gebruiker en werkt gewoon zoals het hoort. Het maakt u niet uit hoe het kopiëren plaatsvindt (of dat het überhaupt plaatsvindt), of op welk specifiek tijdstip de aanwijzer wordt verplaatst.

En de derde consequentie – en hier komen we bij uw probleem – is dat we soms heel vreemd gedrag zien dat moeilijk te begrijpen is. Dit gebeurt met name wanneer u de array zelf probeert te wijzigen, die u in een lus doorloopt.

Een grote verzameling edge-case-gedrag dat optreedt wanneer u een array tijdens iteratie wijzigt, is te vinden in PHP-tests. U kunt met deze test beginnen, vervolgens het adres wijzigen in 012 in 013, enzovoort. Je zult zien hoe elk gedrag zich in verschillende situaties zal manifesteren (allerlei combinaties van schakels, etc.).

Laten we nu teruggaan naar je voorbeelden:

Foreach ($array als $item) ( echo "$item\n"; $array = $item; ) print_r($array); /* Uitvoer in lus: 1 2 3 4 5 $array na lus: 1 2 3 4 5 1 2 3 4 5 */

Hier heeft $array refcount=1 vóór de lus, dus het wordt niet gekopieerd maar krijgt een adresref. Zodra u een waarde aan $array toekent, wordt de zval gesplitst, zodat de array waaraan u elementen toevoegt en de array waarop u itereert twee verschillende arrays zullen zijn.

Foreach ($array as $key => $item) ( $array[$key + 1] = $item + 2; echo "$item\n"; ) print_r($array); /* Uitvoer in lus: 1 2 3 4 5 $array na lus: 1 3 4 5 6 7 */

Dezelfde situatie als bij de eerste test.

// Verplaats de aanwijzer met één om er zeker van te zijn dat deze geen invloed heeft op foreach var_dump(each($array)); foreach ($array als $item) ( echo "$item\n"; ) var_dump(each($array)); /* Uitvoerarray(4) ( => int(1) ["waarde"]=> int(1) => int(0) ["sleutel"]=> int(0) ) 1 2 3 4 5 bool( vals) */

Opnieuw hetzelfde verhaal. Tijdens de foreach-lus heb je refcount=1 en krijg je alleen adresref, de interne $array-aanwijzer zal worden gewijzigd. Aan het einde van de lus wordt de aanwijzer NULL (dit betekent dat de iteratie is voltooid). elk demonstreert dit door false terug te geven.

Foreach ($array as $key => $item) ( echo "$item\n"; Each($array); ) /* Uitvoer: 1 2 3 4 5 */

Foreach ($array as $key => $item) ( echo "$item\n"; reset($array); ) /* Uitvoer: 1 2 3 4 5 */

Maar deze voorbeelden zijn niet overtuigend genoeg. Het gedrag begint echt onvoorspelbaar te worden als je stroom in een lus gebruikt:

Foreach ($array as $val) ( var_dump(current($array)); ) /* Uitvoer: 2 2 2 2 2 */

Hier moet u er rekening mee houden dat stroom ook toegankelijk is via referentie, ondanks dat u de array niet wijzigt. Dit is nodig om consistent te werken met alle andere functies, zoals de volgende, toegang via referentie (current is eigenlijk een ref-functie die de voorkeur heeft; deze kan een waarde krijgen, maar gebruikt een referentie als dat mogelijk is). Een verwijzing betekent dat de array moet worden gescheiden, zodat $array en de kopie van $array die foreach gebruikt onafhankelijk zijn. Waarom u er 2 krijgt en niet 1, wordt hierboven ook vermeld: foreach verhoogt de array-aanwijzer vóór het begin van de gebruikerscode, niet daarna. Dus zelfs als de code nog steeds aan het eerste element werkt, heeft foreach de aanwijzer al naar het tweede verplaatst.

Laten we nu een kleine verandering proberen:

$ref = &$matrix; foreach ($array as $val) ( var_dump(current($array)); ) /* Uitvoer: 2 3 4 5 false */

Hier hebben we is_ref=1, dus de array wordt niet gekopieerd (hetzelfde als hierboven). Maar nu er is_ref is, hoeft de array niet langer te worden gesplitst, waarbij wordt verwezen naar current. Nu werken current en foreach met dezelfde array. Je ziet de array één stap verschuiven, juist vanwege de manier waarop foreach de aanwijzer behandelt.

Je zult hetzelfde zien als je een array doorzoekt door middel van referentie:

Foreach ($array as &$val) ( var_dump(current($array)); ) /* Uitvoer: 2 3 4 5 false */

Het belangrijkste hier is dat foreach onze $array is_ref=1 zal toewijzen wanneer deze er door verwijzing overheen loopt, dus het zal hetzelfde eindigen als hierboven.

Nog een kleine variatie, hier zullen we onze array aan een andere variabele toewijzen:

$foo = $matrix; foreach ($array as $val) ( var_dump(current($array)); ) /* Uitvoer: 1 1 1 1 1 */

Hier is de refcount van $array ingesteld op 2 toen de lus begon, dus er moet een kopie worden gemaakt voordat er wordt gestart. Dus $array en de array die door foreach wordt gebruikt, zullen vanaf het begin verschillend zijn. Daarom krijg je de positie van de interne array-pointer die relevant was voordat de lus begon (in dit geval stond deze op de eerste positie).

Iteratie van objecten

Bij het itereren van objecten is het zinvol om twee gevallen te overwegen:

Het object is niet Traversable (of beter gezegd, de interne get_iterator handler is niet gedefinieerd)

In dit geval vindt iteratie vrijwel hetzelfde plaats als bij arrays. Dezelfde semantiek van kopiëren. Het enige verschil is dat foreach wat extra code zal uitvoeren om eigenschappen over te slaan die niet beschikbaar zijn in het huidige bereik. Nog een paar interessante feiten:

  • Voor gedeclareerde eigenschappen optimaliseert PHP de eigenschappen-hashtabel opnieuw. Als u het object herhaalt, moet het die hashtabel reconstrueren (wat het geheugengebruik verhoogt). Niet dat u zich daar zorgen over hoeft te maken, wees u er wel van bewust.
  • Bij elke iteratie wordt de hashtabel van de eigenschappen opnieuw verkregen, wat betekent dat PHP get_properties keer op keer zal aanroepen. Voor “gewone” eigenschappen is dit niet zo belangrijk, maar als eigenschappen dynamisch worden aangemaakt (dit wordt vaak gedaan door ingebouwde klassen) dan zal de eigenschappentabel elke keer opnieuw worden berekend.
Verplaatsbaar object

In dit geval is alles wat hierboven is gezegd op geen enkele manier van toepassing. Bovendien kopieert PHP niet en gebruikt het geen trucs zoals het verhogen van de aanwijzer vóór het herhalen. Ik denk dat de manier waarop je door een Traversable-object gaat veel voorspelbaarder is en geen verdere beschrijving vereist.

Een iterabele vervangen tijdens een lus

Een ander ongebruikelijk geval dat ik niet heb genoemd, is dat PHP de mogelijkheid biedt om een ​​iterabele tijdens een lus te vervangen. U kunt met één array beginnen en doorgaan door deze halverwege te vervangen door een andere. Of begin met een array en vervang deze door een object:

$arr = ; $obj = (object); $ref =& $arr; foreach ($ref as $val) ( echo "$val\n"; if ($val == 3) ( $ref = $obj; ) ) /* Uitvoer: 1 2 3 6 7 8 9 10 */

Zoals je kunt zien, begon PHP eenvoudigweg de andere entiteit te doorkruisen zodra de vervanging plaatsvond.

Het wijzigen van de interne array-aanwijzer tijdens iteratie

Nog een laatste detail van foreach-gedrag dat ik niet heb genoemd (omdat het kan worden gebruikt om echt vreemd gedrag): wat kan er gebeuren als u de interne array-aanwijzer tijdens een lus probeert te wijzigen.

Hier krijg je misschien niet wat je verwachtte: als je next of prev aanroept in de body van de lus (in het geval van passeren via referentie), zul je zien dat de interne pointer is verplaatst, maar dit heeft geen effect op het gedrag van de iterator. De reden is dat foreach na elke passage van de lus een back-up maakt van de huidige positie en hash van het huidige element in de HashPointer. Bij de volgende doorgang zal foreach controleren of de positie van de interne aanwijzer is veranderd en proberen deze te herstellen met behulp van deze hash.

Laten we eens kijken wat "zal proberen" betekent. Het eerste voorbeeld laat zien hoe het wijzigen van de interne aanwijzer de foreach-modus niet verandert:

$matrix = ; $ref =& $matrix; foreach ($array as $value) (var_dump($value); reset($array); ) // uitvoer: 1, 2, 3, 4, 5

Laten we nu proberen het element uit te schakelen waartoe foreach toegang krijgt bij de eerste doorgang (sleutel 1):

$matrix = ; $ref =& $matrix; foreach ($array as $value) ( ​​var_dump($value); unset($array); reset($array); ) // uitvoer: 1, 1, 3, 4, 5

Hier zie je dat de teller wordt gereset omdat een element met een bijpassende hash niet kon worden gevonden.

Houd er rekening mee dat een hasj slechts een hasj is. Botsingen gebeuren. Laten we dit nu proberen:

$array = ["EzEz" => 1, "EzFY" => 2, "FYEz" => 3]; $ref =& $matrix; foreach ($array as $value) ( ​​unset($array["EzFY"]); $array["FYFZ"] = 4; reset($array); var_dump($value); ) // uitvoer: 1 1 3 4

Werkt zoals we verwacht hadden. We hebben de EzFY-sleutel verwijderd (degene waar foreach zich bevond), dus er is een reset uitgevoerd. Ook hebben we er een extra sleutel bij gedaan, zodat we er 4 aan het einde zien.

En hier komt het onbekende. Wat gebeurt er als u de FYFY-sleutel vervangt door FYFZ? Laten we proberen:

$array = ["EzEz" => 1, "EzFY" => 2, "FYEz" => 3]; $ref =& $matrix; foreach ($array as $value) ( ​​unset($array["EzFY"]); $array["FYFY"] = 4; reset($array); var_dump($value); ) // uitvoer: 1 4

Nu is de lus rechtstreeks naar het nieuwe element verplaatst en wordt al het andere overgeslagen. Dit komt omdat de FYFY-sleutel een botsing heeft met EzFY (eigenlijk ook alle sleutels uit deze array). Bovendien bevindt het FYFY-element zich op hetzelfde geheugenadres als het EzFY-element dat zojuist is verwijderd. Voor PHP zal het dus dezelfde positie zijn met dezelfde hash. De positie wordt “hersteld” en de overgang naar het einde van de array vindt plaats.

Vaak moet je alle elementen van een PHP-array doorlopen en een bewerking op elk element uitvoeren. U kunt bijvoorbeeld elke waarde naar een HTML-tabel uitvoeren of elk element een nieuwe waarde geven.

In deze les zullen we kijken naar de foreach-constructie bij het organiseren van een lus over geïndexeerde en bijbehorende arrays.

Loop door elementwaarden

Het eenvoudigste gebruiksscenario voor foreach is het doorlussen van waarden in een geïndexeerde array. Basissyntaxis:

Foreach ($array as $value) ( ​​// Doe iets met $value ) // Hier wordt de code uitgevoerd nadat de lus is voltooid

Het volgende script doorloopt bijvoorbeeld de lijst met regisseurs in een geïndexeerde array en drukt de naam van elk af:

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

De bovenstaande code levert het volgende op:

Alfred Hitchcock Stanley Kubrick Martin Scorsese Fritz Lang

Sleutel-waarde-lus

Hoe zit het met de bijbehorende arrays? Wanneer u dit type array gebruikt, moet u vaak toegang hebben tot de sleutel van elk element en tot de waarde ervan. De foreach-constructie heeft een manier om het probleem op te lossen:

Foreach ($array as $key => $value) ( ​​// Doe iets met $key en/of $value ) // Hier wordt de code uitgevoerd nadat de lus is voltooid

Een voorbeeld van het organiseren van een lus door een bijbehorende array met informatie over films, waarbij de sleutel van elk element en de waarde ervan wordt weergegeven in de HTML-lijst met definities:

$movie = array("title" => "Achterruit", "regisseur" => "Alfred Hitchcock", "jaar" => 1954, "minuten" => 112); echo "

"; foreach ($film als $key => $value) ( ​​​echo "
$sleutel:
"; echo"
$waarde
";) echo"
";

Wanneer het wordt uitgevoerd, zal dit script het volgende opleveren:

Titel: Rear Window regisseur: Alfred Hitchcock jaar: 1954 minuten: 112

De waarde van een element wijzigen

Hoe zit het met het veranderen van de waarde van een element terwijl de lus doorloopt? Je kunt deze code proberen:

Foreach ($myArray als $value) ( ​​$value = 123; )

Als u het echter uitvoert, zult u merken dat de waarden in de array verander niet. De reden is dat foreach werkt met een kopie arraywaarden, niet met het origineel. Op deze manier blijft de originele array intact.

Om arraywaarden te wijzigen die u nodig hebt link naar de betekenis. Om dit te doen, moet je een &-teken voor de waardevariabele in de foreach-constructie plaatsen:

Foreach ($myArray as &$value) ( ​​$value = 123; )

Het volgende script doorloopt bijvoorbeeld elk element (naam van de regisseur) in de array $directors en gebruikt de PHP explode()-functie en de lijstconstructie om de voor- en achternaam om te draaien:

$directors = array("Alfred Hitchcock", "Stanley Kubrick", "Martin Scorsese", "Fritz Lang"); // Wijzig het naamformaat voor elk element foreach ($directors as &$director) ( list($firstName, $lastName) = explode(" ", $director); $director = "$lastName, $firstName"; ) unset ($directeur); // Druk het eindresultaat foreach ($directors as $director) af ( echo $director . "
"; }

Het script levert het volgende op:

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

Houd er rekening mee dat het script de functie unset() aanroept om de variabele $director te verwijderen nadat de eerste lus is voltooid. Dit is een goede gewoonte als u van plan bent de variabele later in het script in een andere context te gebruiken.

Als u de verwijzing niet verwijdert, loopt u het risico dat u code blijft uitvoeren die per ongeluk verwijst naar het laatste element in de array ("Lang, Fritz") als u de variabele $director blijft gebruiken, wat tot onbedoelde gevolgen zal leiden!

Cv

In deze tutorial hebben we gekeken hoe we de PHP foreach-constructie kunnen gebruiken om door de elementen van een array te lopen. De volgende kwesties werden overwogen:

  • Hoe u door array-elementen loopt
  • Hoe u toegang krijgt tot de sleutel en waarde van elk element
  • Hoe u een referentie gebruikt om waarden te wijzigen terwijl u door een lus gaat

Stel je voor dat je een associatieve array hebt die je wilt herhalen. PHP biedt een eenvoudige manier om elk element van een array achtereenvolgens te gebruiken met behulp van de Foreach-constructie.

In eenvoudige taal zou het ongeveer zo klinken:
"Voer deze code uit voor elk element in de opgegeven array."

Hoewel deze doorgaat zolang aan een bepaalde voorwaarde wordt voldaan, zal de foreach-lus doorgaan totdat hij elk element van de array heeft doorlopen.

PHP Foreach: voorbeeld

We hebben een associatieve array waarin de namen van mensen in ons bedrijf worden opgeslagen, evenals hun leeftijd. We willen weten hoe oud elke werknemer is, dus gebruiken we een for-each-lus om ieders naam en leeftijd af te drukken.

$employeeAges; $employeeAges["Lisa"] = "28"; $employeeAges["Jack"] = "16"; $employeeAges["Ryan"] = "35"; $employeeAges["Rachel"] = "46"; $employeeAges["Grace"] = "34"; foreach($employeeAges as $key => $value)( echo "Naam: $key, Leeftijd: $value
"; }

We krijgen het resultaat:

Naam: Lisa, leeftijd: 28 Naam: Jack, leeftijd: 16 Naam: Ryan, leeftijd: 35 Naam: Rachel, leeftijd: 46 Naam: Grace, leeftijd: 34

Welnu, het resultaat is goed en begrijpelijk, maar de syntaxis van het foreach-construct is niet erg eenvoudig en begrijpelijk. Laten we het eens nader bekijken.

Voor elke syntaxis: $something as $key => $value

Al deze waanzin vertaalt zich grofweg in: “Voor elk element van de associatieve array $employeeAges wil ik toegang krijgen tot $key en de waarde daarin, namelijk $value.

De operator "=>" vertegenwoordigt de relatie tussen een sleutel en een waarde. In ons voorbeeld hebben we ze de naam key - $key en value - $value gegeven. Het zou echter gemakkelijker zijn om ze als naam en leeftijd te beschouwen. In ons voorbeeld hieronder doen we precies dat en merken we op dat het resultaat hetzelfde zal zijn, omdat we alleen de namen hebben gewijzigd van de variabelen die naar de sleutels en waarden verwijzen.

$employeeAges; $employeeAges["Lisa"] = "28"; $employeeAges["Jack"] = "16"; $employeeAges["Ryan"] = "35"; $employeeAges["Rachel"] = "46"; $employeeAges["Grace"] = "34"; foreach($employeeAges as $name => $age)( echo "Naam: $name, Leeftijd: $age
"; }

Welnu, het resultaat is, herhalen we, hetzelfde.