Acasă - Configurare Internet
Pentru fiecare valoare php a următoarelor. face bucle while și foreach

face bucle while și foreach

face bucla . . in timp ce

face...while buclaîn C# aceasta este o versiune a while cu o verificare post-condiție. Aceasta înseamnă că starea buclei este verificată după ce corpul buclei este executat. Prin urmare, buclele do...while sunt utile în situațiile în care un bloc de instrucțiuni trebuie executat cel puțin o dată. Următoarea este forma generală a unei instrucțiuni de buclă do-while:

do (operatori; ) while (condiție);

Dacă există un singur operator, acolade în această formă de notație sunt opționale. Cu toate acestea, ele sunt adesea folosite pentru a face construcția do-while mai lizibilă și pentru a nu fi confundate cu construcția buclei while. Bucla do-while rulează atâta timp cât expresia condiționată este adevărată. Un exemplu de utilizare a unei bucle do-while este următorul program, care calculează factorialul unui număr:

Utilizarea sistemului; folosind System.Collections.Generic; folosind System.Linq; folosind System.Text; namespace ConsoleApplication1 ( class Program ( static void Main(string args)) ( try ( // Calculați factorialul unui număr int i, rezultat = 1, num = 1; Console.WriteLine("Introduceți un număr:"); i = int .Parse(Console .ReadLine()); Console.Write("\n\nFactorial (0) = ", i); do (rezultat *= num; num++; ) while (num

bucla foreach

bucla foreach servește pentru accesul ciclic la elementele unei colecții, care este un grup de obiecte. C# definește mai multe tipuri de colecții, fiecare dintre acestea fiind o matrice. Următoarea este forma generală a instrucțiunii buclei foreach:

foreach (de tip loop_variable_name în colecție) instrucțiune;

Aici tastați nume_variabilă_buclă denotă tipul și numele variabilei de control al buclei care primește valoarea următorului element al colecției la fiecare pas al buclei foreach. Și colecția denotă o colecție interogată ciclic, care în continuare reprezintă o matrice. Prin urmare, tipul variabilei buclei trebuie să se potrivească cu tipul elementului de matrice. În plus, un tip poate fi notat cu cuvântul cheie var. În acest caz, compilatorul determină tipul variabilei buclei pe baza tipului elementului de matrice. Acest lucru poate fi util pentru a lucra cu anumite tipuri de interogări. Dar, de regulă, tipul este specificat în mod explicit.

Instrucțiunea buclă foreach funcționează după cum urmează. Când începe bucla, primul element al matricei este selectat și atribuit variabilei buclei. La fiecare pas de iterație următor, următorul element de matrice este selectat și stocat într-o variabilă de buclă. Bucla se termină când sunt selectate toate elementele matricei.

O buclă foreach vă permite să parcurgeți fiecare element al unei colecții (un obiect care reprezintă o listă de alte obiecte). Din punct de vedere tehnic, pentru ca ceva să fie considerat o colecție, trebuie să suporte interfața IEnumerable. Exemplele de colecții includ matrice C#, clase de colecții din spațiul de nume System.Collection și clase de colecții personalizate.

Bucla For Each...Next din VBA Excel, sintaxa acesteia și descrierea componentelor individuale. Exemple de utilizare a buclei For Each...Next.

Bucla For Each... Next din VBA Excel este concepută pentru a executa un bloc de instrucțiuni în relație cu fiecare element dintr-un grup de elemente (gamă, matrice, colecție). Această buclă minunată este folosită atunci când numărul de elemente dintr-un grup și indexarea lor sunt necunoscute, altfel este de preferat să folosiți .

Pentru fiecare... Sintaxa buclei următoare

Pentru fiecare element În grup [ declarații ] [ Ieșire pentru ] [ instrucțiuni ] Următorul [ element ]

Parantezele pătrate indică atributele opționale ale buclei For Each...Next.

Componentele unei bucle pentru fiecare... Următoarea buclă

*Dacă o buclă For Each...Next este utilizată în VBA Excel pentru a itera prin elementele unei colecții (obiect de colecție) sau ale unei matrice, atunci variabila element trebuie declarat cu un tip de date Variantă, altfel bucla nu va funcționa.

**Dacă nu folosiți propriul cod într-o buclă, se pierde sensul utilizării unei bucle.

Exemple de bucle For Each...Next

Buclă peste o serie de celule

Pe foaia activă a registrului de lucru Excel, selectați o serie de celule și rulați următoarea procedură:

Sub test1() Dim element As Range, a As String a = "Date obținute de For Each... Next:" Pentru fiecare element din Selecție a = a & vbNewLine & "Cell " & element.Address & _ " conține valoarea : " & CStr(element.Value) Next MsgBox a End Sub

Fereastra de informații MsgBox va afișa adresele celulelor selectate și conținutul acestora, dacă există. Dacă sunt selectate multe celule, atunci informațiile complete despre toate celulele nu vor fi afișate, deoarece lungimea maximă a parametrului Prompt are aproximativ 1024 de caractere.

Bucla pentru o colecție de foi

Copiați următoarea procedură VBA în registrele de lucru Excel:

Sub test2() Dim element As Worksheet, a As String a = "Lista de foi conținute în această foaie de lucru:" Pentru fiecare element din foile de lucru a = a & vbNewLine & element.Index _ & ") " & element.Name Next MsgBox a End Sub

Fereastra de informații MsgBox va afișa o listă cu numele tuturor foilor din registrul de lucru Excel după numărul de serie al etichetelor lor corespunzător indicilor lor.

Buclă pentru o matrice

Să atribuim o listă de nume de animale matricei și să le scriem într-o variabilă din bucla For Each... Următoarea A. Fereastra de informații MsgBox va afișa o listă de nume de animale din variabilă A.

Sub test3() Dim element As Variant, a As String, group As Variant group = Array ("hipopotam", "elephant", "cangaroo", "tigru", "mouse") "sau puteți atribui valorile lui intervalul de celule ale „lucrătorului” la foaia de matrice, de exemplu, selectat: grup = Selecție a = „Matricea conține următoarele valori:” & vbNewLine Pentru fiecare element din grup a = a & vbNewLine & element Next MsgBox a End Sub

Să repetăm ​​aceeași procedură VBA, dar să atribuim valoarea „Papagal” tuturor elementelor matricei din bucla For Each...Next. Fereastra de informații MsgBox va afișa o listă de nume de animale, constând doar din papagali, ceea ce demonstrează că este posibilă editarea valorilor elementelor matricei în bucla For Each...Next.

Sub test4() Dim element As Variant, a As String, group As Variant group = Array ("hipopotam", "elephant", "cangaroo", "tigru", "mouse") "sau puteți atribui valorile lui intervalul de celule ale „lucrătorului” la foaia matrice, de exemplu, cea selectată: grup = Selecție a = „Matricea conține următoarele valori:” & vbNewLine Pentru fiecare element În elementul grup = „Papagal” a = a & vbNewLine & element Next MsgBox a End Sub

Acest cod, ca toate celelalte din acest articol, a fost testat în Excel 2016.

Parcurgeți o colecție de subdirectoare și ieșiți din buclă

În acest exemplu vom adăuga variabilei A numele subdirectoarelor de pe disc C computerul tau. Când bucla ajunge la folder Fișiere de program, se va adăuga la variabilă A titlul și mesajul acestuia: „Destul, nu voi citi mai departe! Cu stimă, pentru fiecare... Următorul ciclu."

Sub test5() Dim FSO As Object, myFolders As Object, myFolder As Object, a As String "Creați un nou FileSystemObject și atribuiți-l variabilei "FSO" Set FSO = CreateObject("Scripting.FileSystemObject") "Preluați lista de subdirectoarele de pe unitatea „C” „ și atribuiți „o variabilei „myFolders” Set myFolders = FSO.GetFolder(“C:\”) a = „Foldere de pe unitatea C:” & vbNewLine „Parcurgem lista de subdirectoare și adăugați numele lor la variabila „a” După ce am ajuns în folderul „Program Files”, ieșim din ciclul Pentru fiecare myFolder În myFolders.SubFolders a = a & vbNewLine & myFolder.Name Dacă myFolder.Name = „Program Files” Apoi a = a & vbNewLine & vbNewLine & „Este suficient, citiți mai departe, nu voi face!” _ & vbNewLine & vbNewLine & „Cu respect,” & vbNewLine & _ „Bucla dumneavoastră este pentru fiecare... Următorul.” Ieșire pentru sfârșit dacă se setează următorul FSO = Nothing MsgBox a End Sub

Fereastra de informații MsgBox va afișa o listă de nume de subdirectoare de pe disc C computerul dvs. în folder Fișiere de program inclusiv și un mesaj din ciclu despre încetarea activității sale.

Ca urmare a funcționării programului, nu vor fi afișate numai numele subdirectoarelor vizibile la navigarea pe disc în Explorer. C, dar și foldere ascunse și de service. Pentru a vizualiza o listă a tuturor subdirectoarelor de pe un disc C, comentați secțiunea de cod din Dacă inainte de Încheiați dacă inclusiv și rulați procedura în editorul VBA Excel.

Adesea trebuie să parcurgeți toate elementele unei matrice PHP și să efectuați o operațiune pe fiecare element. De exemplu, puteți scoate fiecare valoare într-un tabel HTML sau puteți da fiecărui element o nouă valoare.

În această lecție ne vom uita la constructul foreach atunci când organizăm o buclă peste matrice indexate și asociate.

Buclă prin valorile elementelor

Cel mai simplu caz de utilizare pentru foreach este să faci bucla prin valori într-o matrice indexată. Sintaxa de baza:

Foreach ($array ca $valoare) ( ​​// Faceți ceva cu $valoare ) // Aici codul este executat după finalizarea buclei

De exemplu, următorul script iterează prin lista de directori dintr-o matrice indexată și tipărește numele fiecăruia:

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

Codul de mai sus va scoate:

Alfred Hitchcock Stanley Kubrick Martin Scorsese Fritz Lang

Bucla cheie-valoare

Dar matricele asociate? Când utilizați acest tip de matrice, deseori trebuie să aveți acces la cheia fiecărui element, precum și la valoarea acestuia. Construcția foreach are o modalitate de a rezolva problema:

Foreach ($array ca $key => $value) ( ​​​​// Faceți ceva cu $key și/sau $value ) // Aici codul este executat după finalizarea buclei

Un exemplu de organizare a unei bucle printr-o matrice asociată cu informații despre filme, afișând cheia fiecărui element și valoarea acestuia în lista HTML de definiții:

$movie = array("title" => "Luneta", "director" => "Alfred Hitchcock", "an" => 1954, "minute" => 112); ecou"

"; foreach ($movie ca $key => $value) ( ​​​​echo "
$key:
"; ecou"
$valoare
";) ecou"
";

Când este executat, acest script va scoate:

Titlu: Geam Regizor: Alfred Hitchcock Anul: 1954 minute: 112

Modificarea valorii unui element

Ce zici de schimbarea valorii unui element pe măsură ce trece bucla? Puteți încerca acest cod:

Foreach ($myArray ca $valoare) ( ​​$valoare = 123; )

Cu toate acestea, dacă îl rulați, veți descoperi că valorile din matrice nu schimba. Motivul este că foreach funcționează cu o copie valorile matricei, nu cu originalul. În acest fel, matricea originală rămâne intactă.

Pentru a schimba valorile matricei aveți nevoie legătură la sens. Pentru a face acest lucru, trebuie să puneți un semn & în fața variabilei valoare în constructul foreach:

Foreach ($myArray ca &$valoare) ( ​​$value = 123; )

De exemplu, următorul script parcurge fiecare element (numele directorului) din matricea $directors și folosește funcția PHP explode() și construcția listă pentru a schimba numele și numele:

$directori = array("Alfred Hitchcock", "Stanley Kubrick", "Martin Scorsese", "Fritz Lang"); // Schimbați formatul numelui pentru fiecare element pentru fiecare ($directori ca &$director) ( list($firstName, $lastName) = explode(" ", $director); $director = "$lastName, $firstName"; ) unset ( $director); // Imprimă rezultatul final pentru fiecare ($directori ca $director) ( echo $director . "
"; }

Scriptul va afișa:

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

Rețineți că scriptul apelează funcția unset() pentru a elimina variabila $director după terminarea primei bucle. Aceasta este o practică bună dacă intenționați să utilizați variabila mai târziu în script într-un context diferit.

Dacă nu eliminați referința, riscați să executați în continuare cod care face referire accidentală la ultimul element din matrice ("Lang, Fritz") dacă continuați să utilizați variabila $director, ceea ce va duce la consecințe nedorite!

rezumat

În acest tutorial, ne-am uitat la cum să folosim construcția PHP foreach pentru a parcurge elementele unui tablou. Au fost luate în considerare următoarele aspecte:

  • Cum să parcurgeți elementele matricei
  • Cum se accesează cheia și valoarea fiecărui element
  • Cum să utilizați o referință pentru a schimba valorile pe măsură ce treceți printr-o buclă

Într-un rezumat recent de link-uri interesante despre PHP, am găsit un link către un comentariu al lui Nikita Popov pe StackOverflow, unde vorbește în detaliu despre mecanismul „sub capota” al constructului de control foreach.
Deoarece foreach funcționează uneori în moduri mai mult decât puțin ciudate, mi s-a părut util să traduc acest răspuns.

Atenție: acest text presupune cunoștințe de bază despre funcționalitatea zvals în PHP, în special ar trebui să știți ce sunt refcount și is_ref.
foreach funcționează cu entități de diferite tipuri: cu matrice, cu obiecte simple (unde sunt listate proprietățile disponibile) și cu obiecte Traversable (sau mai degrabă, obiecte care au un handler intern get_iterator definit). Aici vorbim în mare parte despre matrice, dar despre restul voi vorbi la final.

Înainte de a începe, câteva cuvinte despre matrice și parcurgerea lor, importante pentru înțelegerea contextului.

Cum funcționează traversarea matricei?

Matricele în PHP sunt tabele hash ordonate (elementele hash sunt combinate într-o listă dublu legată) și foreach traversează tabloul urmând ordinea specificată.

PHP include două moduri de a parcurge o matrice:

  • Prima modalitate este un pointer de matrice intern. Acest pointer face parte din structura HashTable și este pur și simplu un pointer către elementul curent al tabelului hash. Pointerul matricei intern poate fi schimbat cu impunitate, adică dacă elementul curent este șters, pointerul matricei intern va fi mutat la următorul.
  • Al doilea mecanism de iterație este un pointer de matrice extern numit HashPosition. Acesta este în esență același cu un pointer de matrice intern, dar nu face parte din HashTable. Acest mod extern de iterare nu este sigur pentru schimbare. Dacă eliminați elementul indicat de HashPosition, veți rămâne cu un indicator care atârnă, ceea ce va duce la o eroare de segmentare.

Astfel, pointerii de matrice externe ar trebui să fie utilizați numai atunci când sunteți absolut sigur că niciun cod de utilizator nu va fi executat în timpul traversării. Și un astfel de cod poate ajunge în cele mai neașteptate locuri, cum ar fi un handler de erori sau un destructor. Acesta este motivul pentru care, în majoritatea cazurilor, PHP trebuie să folosească un pointer intern în loc de unul extern. Dacă ar fi altfel, PHP s-ar putea bloca cu o eroare de segmentare de îndată ce utilizatorul începe să facă ceva neobișnuit.

Problema cu indicatorul intern este că face parte din HashTable. Deci, atunci când îl schimbați, HashTable se schimbă odată cu el. Și din moment ce matricele în PHP sunt accesate după valoare (și nu prin referință), ești forțat să copiați matricea pentru a parcurge elementele sale.

Un exemplu simplu care arată importanța copierii (nu atât de neobișnuit, apropo) este iterația imbricată:

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

Aici doriți ca ambele bucle să fie independente și să nu fie aruncate în mod inteligent cu un singur indicator.

Deci ajungem la foreach.

Parcurgerea unei matrice în foreach

Acum știți de ce foreach trebuie să creeze o copie a matricei înainte de a o traversa. Dar aceasta nu este în mod clar toată povestea. Dacă PHP face o copie sau nu depinde de mai mulți factori:

  • Dacă matricea iterabilă este o referință, nu va avea loc nicio copiere, ci va fi executată adresa:

    $ref =& $matrice; // $array are is_ref=1 acum pentru fiecare ($array ca $val) ( // ... )
    De ce? Deoarece orice modificare a matricei trebuie propagată prin referință, inclusiv pointerul intern. Dacă foreach a făcut o copie în acest caz, ar rupe semantica legăturii.

  • Dacă matricea are refcount=1, copierea nu va fi din nou efectuată. refcount=1 înseamnă că tabloul nu este folosit în altă parte și foreach îl poate folosi direct. Dacă refcount este mai mare de unu, atunci matricea este partajată cu alte variabile și pentru a evita modificarea, foreach trebuie să o copieze (indiferent de cazul de referință descris mai sus).
  • Dacă matricea este traversată de referință (foreach ($array ca &$ref)), atunci - indiferent de funcția de copiere sau non-copiere - matricea va deveni o referință.

Deci aceasta este prima parte a misterului: funcția de copiere. A doua parte este modul în care este executată iterația curentă și este, de asemenea, destul de ciudată. Modelul de iterație „normal” pe care îl cunoașteți deja (și care este adesea folosit în PHP - separat de foreach) arată cam așa (pseudocod):

Resetare(); în timp ce (get_current_data(&date) == SUCCES) (code(); move_forward(); )
pentru fiecare iterație arată puțin diferit:

Resetare(); în timp ce (get_current_data(&date) == SUCCES) ( move_forward(); code(); )

Diferența este că move_forward() este executat mai degrabă la început decât la sfârșitul buclei. Astfel, când codul utilizatorului folosește elementul $i, pointerul matricei intern indică deja elementul $i+1.

Acest mod de operare al foreach este, de asemenea, motivul pentru care pointerul matricei intern se mută la următorul element dacă cel curent este șters, mai degrabă decât la cel anterior (cum v-ați putea aștepta). Totul este conceput să funcționeze grozav cu foreach (dar, evident, nu va funcționa la fel de bine cu orice altceva, sărind elemente).

Implicațiile codului

Prima consecință a comportamentului de mai sus este că foreach copiază matricea iterabilă în multe cazuri (încet). Dar nu vă temeți: am încercat să elimin cerința de copiere și nu am putut vedea nicio accelerare nicăieri decât în ​​benchmark-urile artificiale (care au repetat cu o viteză de două ori mai mare). Se pare că oamenii pur și simplu nu repetă suficient.

A doua consecință este că de obicei nu ar trebui să existe alte consecințe. Comportamentul foreach este, în general, destul de înțeles de utilizator și funcționează așa cum ar trebui. Nu ar trebui să vă pese cum are loc copierea (sau dacă are loc deloc), sau în ce moment specific este mutat indicatorul.

Și a treia consecință - și aici ajungem la problema ta - este că uneori vedem un comportament foarte ciudat, greu de înțeles. Acest lucru se întâmplă în special atunci când încercați să modificați matricea în sine, pe care o traversați într-o buclă.

O colecție mare de comportamente de cazuri marginale care apare atunci când modificați o matrice în timpul iterației poate fi găsită în testele PHP. Puteți începe cu acest test, apoi schimbați 012 în 013 în adresă și așa mai departe. Veți vedea cum se va manifesta fiecare comportament în diferite situații (tot felul de combinații de link-uri etc.).

Acum să revenim la exemplele tale:

Foreach ($array ca $item) ( echo "$item\n"; $array = $item; ) print_r($array); /* Ieșire în buclă: 1 2 3 4 5 $matrice după buclă: 1 2 3 4 5 1 2 3 4 5 */

Aici $array are refcount=1 înaintea buclei, așa că nu va fi copiat, dar va primi adresa. Odată ce atribuiți o valoare lui $array, zval-ul va fi împărțit, astfel încât matricea la care adăugați elemente și matricea pe care o iterați vor fi două matrice diferite.

Foreach ($array ca $key => $item) ( $array[$key + 1] = $item + 2; echo "$item\n"; ) print_r($array); /* Ieșire în buclă: 1 2 3 4 5 $matrice după buclă: 1 3 4 5 6 7 */

Aceeași situație ca la primul test.

// Deplasați indicatorul cu unul pentru a vă asigura că nu afectează foreach var_dump(each($array)); foreach ($array ca $item) ( echo "$item\n"; ) var_dump(each($array)); /* Matrice de ieșire(4) ( => int(1) ["valoare"] => int(1) => int(0) ["key"] => int(0) ) 1 2 3 4 5 bool( fals) */

Din nou aceeași poveste. În timpul buclei foreach, aveți refcount=1 și obțineți doar adresa, pointerul intern $array va fi modificat. La sfârșitul buclei, pointerul devine NULL (aceasta înseamnă că iterația este finalizată). fiecare demonstrează acest lucru returnând false.

Foreach ($array ca $key => $item) ( echo „$item\n”; fiecare ($array); ) /* Ieșire: 1 2 3 4 5 */

Foreach ($array ca $key => $item) ( echo „$item\n”; reset($array); ) /* Ieșire: 1 2 3 4 5 */

Dar aceste exemple nu sunt suficient de convingătoare. Comportamentul începe să devină cu adevărat imprevizibil atunci când utilizați curentul într-o buclă:

Foreach ($array ca $val) ( var_dump(current($array)); ) /* Ieșire: 2 2 2 2 2 */

Aici ar trebui să rețineți că curentul este accesat și prin referință, în ciuda faptului că nu ați modificat matricea. Acest lucru este necesar pentru a funcționa în mod consecvent cu toate celelalte funcții, ca în continuare, accesul prin referință (curent este de fapt o funcție de referință preferabilă; poate obține o valoare, dar folosește o referință dacă poate). O referință înseamnă că matricea trebuie separată, deci $array și copia lui $array pe care o folosește foreach vor fi independente. De ce obțineți 2 și nu 1 este de asemenea menționat mai sus: foreach increments array pointer înainte de începerea codului de utilizator, nu după. Deci, chiar dacă codul încă funcționează pe primul element, foreach a mutat deja indicatorul la al doilea.

Acum să încercăm o mică schimbare:

$ref = &$array; foreach ($array ca $val) ( var_dump(current($array)); ) /* Ieșire: 2 3 4 5 false */

Aici avem is_ref=1, deci matricea nu este copiată (la fel ca mai sus). Dar acum că există is_ref, matricea nu mai trebuie împărțită, trecând prin referință la curent. Acum curent și foreach funcționează cu aceeași matrice. Vedeți matricea deplasată cu unul tocmai din cauza modului în care foreach tratează pointerul.

Veți vedea același lucru când parcurgeți o matrice prin referință:

Foreach ($array ca &$val) ( var_dump(current($array)); ) /* Ieșire: 2 3 4 5 false */

Lucrul important aici este că foreach va atribui $array-ul nostru is_ref=1 atunci când trece peste el prin referință, așa că va ajunge la fel ca mai sus.

O altă mică variație, aici vom aloca matricea noastră unei alte variabile:

$foo = $array; foreach ($array ca $val) ( var_dump(current($array)); ) /* Ieșire: 1 1 1 1 1 */

Aici refcount-ul $array este setat la 2 când bucla a început, deci trebuie făcută o copie înainte de a începe. Deci $array și matricea folosită de foreach vor fi diferite de la început. De aceea obțineți poziția pointerului matricei interne care era relevantă înainte de începerea buclei (în acest caz era în prima poziție).

Iterația obiectelor

Când iterați obiecte, este logic să luați în considerare două cazuri:

Obiectul nu este Traversabil (sau mai degrabă, handlerul intern get_iterator nu este definit)

În acest caz, iterația are loc aproape la fel ca în cazul tablourilor. Aceeași semantică a copierii. Singura diferență este că foreach va rula un cod suplimentar pentru a omite proprietățile care nu sunt disponibile în domeniul actual. Încă câteva fapte interesante:

  • Pentru proprietățile declarate, PHP reoptimizează tabelul hash al proprietăților. Dacă repeți obiectul, acesta trebuie să reconstruiască acel tabel hash (care crește utilizarea memoriei). Nu că ar trebui să-ți faci griji pentru asta, doar fii conștient.
  • La fiecare iterație, tabelul hash de proprietăți va fi reobținut, ceea ce înseamnă că PHP va apela get_properties din nou și din nou și din nou. Pentru proprietățile „obișnuite”, acest lucru nu este atât de important, dar dacă proprietățile sunt create dinamic (acest lucru se face adesea prin clase încorporate), atunci tabelul de proprietăți va fi recalculat de fiecare dată.
Obiect traversabil

În acest caz, tot ceea ce s-a spus mai sus nu se va aplica în niciun fel. De asemenea, PHP nu va copia și nu va folosi niciun fel de trucuri, cum ar fi incremente de pointer înainte de bucla. Cred că modul de trecere printr-un obiect Traversabil este mult mai previzibil și nu necesită o descriere ulterioară.

Înlocuirea unui iterabil în timpul unei bucle

Un alt caz neobișnuit pe care nu l-am menționat este că PHP permite posibilitatea de a înlocui un iterabil în timpul unei bucle. Puteți începe cu o matrice și puteți continua prin înlocuirea acesteia cu alta la jumătate. Sau începeți cu o matrice, apoi înlocuiți-o cu un obiect:

$arr = ; $obj = (obiect) ; $ref =& $arr; foreach ($ref ca $val) ( echo "$val\n"; if ($val == 3) ( $ref = $obj; ) ) ) /* Ieșire: 1 2 3 6 7 8 9 10 */

După cum puteți vedea, PHP a început pur și simplu să traverseze cealaltă entitate de îndată ce a avut loc înlocuirea.

Schimbarea indicatorului matricei interne în timpul iterației

Un ultim detaliu al fiecărui comportament pe care nu l-am menționat (pentru că poate fi folosit pentru a obține comportament cu adevărat ciudat): ce se poate întâmpla dacă încercați să schimbați indicatorul matricei interne în timpul unei bucle.

Aici este posibil să nu obțineți ceea ce vă așteptați: dacă apelați next sau prev în corpul buclei (în cazul trecerii prin referință), veți vedea că pointerul intern s-a mutat, dar acest lucru nu are niciun efect asupra comportamentului iteratorul. Motivul este că foreach face o copie de rezervă a poziției curente și a hash-ului elementului curent în HashPointer după fiecare trecere a buclei. La următoarea trecere, foreach va verifica dacă poziția indicatorului intern s-a schimbat și va încerca să o restabilească folosind acest hash.

Să vedem ce înseamnă „voi încerca”. Primul exemplu arată cum schimbarea indicatorului intern nu schimbă modul pentru fiecare:

$matrice = ; $ref =& $matrice; foreach ($array ca $valoare) ( ​​var_dump($valoare); reset($array); ) // ieșire: 1, 2, 3, 4, 5

Acum să încercăm să dezactivăm elementul pe care foreach îl va accesa la prima trecere (tasta 1):

$matrice = ; $ref =& $matrice; foreach ($array ca $valoare) ( ​​var_dump($valoare); unset($array); reset($array); ) // ieșire: 1, 1, 3, 4, 5

Aici veți vedea că contorul a fost resetat deoarece nu a putut fi găsit un element cu un hash potrivit.

Ține minte, un hașu este doar un haș. Se produc coliziuni. Să încercăm asta acum:

$array = ["EzEz" => 1, "EzFY" => 2, "FYEz" => 3]; $ref =& $matrice; foreach ($array ca $valoare) ( ​​unset($array["EzFY"]); $array["FYFZ"] = 4; reset($array); var_dump($valoare); ) // ieșire: 1 1 3 4

Funcționează așa cum ne așteptam. Am eliminat cheia EzFY (cea în care a fost localizat foreach), așa că a fost făcută o resetare. Am adăugat și o cheie suplimentară, așa că vedem 4 la sfârșit.

Și aici vine necunoscutul. Ce se întâmplă dacă înlocuiți cheia FYFY cu FYFZ? Sa incercam:

$array = ["EzEz" => 1, "EzFY" => 2, "FYEz" => 3]; $ref =& $matrice; foreach ($array ca $valoare) ( ​​unset($array["EzFY"]); $array["FYFY"] = 4; reset($array); var_dump($valoare); ) // ieșire: 1 4

Acum bucla s-a mutat direct la noul element, sărind peste orice altceva. Acest lucru se datorează faptului că cheia FYFY are o coliziune cu EzFY (de fapt, toate cheile din această matrice). Mai mult, elementul FYFY este situat la aceeași adresă de memorie ca și elementul EzFY care tocmai a fost șters. Deci pentru PHP va fi aceeași poziție cu același hash. Poziția este „restaurată” și are loc tranziția la sfârșitul matricei.

Construcția foreach este o variație a lui for care este inclusă în limbaj pentru a face iterația peste elementele unei matrice mai ușoară. Există două versiuni ale comenzii foreach, concepute pentru diferite tipuri de matrice:

foreach (matrice ca $element) (

foreach (matrice ca $key => $element) (

De exemplu, când executați următorul fragment:

$menu = аrrау("paste", "friptură", "cartofi", "pește", "cartofi prăjiți");

foreach ($meniu ca $articol) (

tipăriți „$item
";

va fi rezultat următorul rezultat:

Există două lucruri de remarcat în acest exemplu. În primul rând, constructul foreach revine automat la începutul matricei (acest lucru nu se întâmplă în alte constructe în buclă). În al doilea rând, nu este nevoie să incrementați în mod explicit contorul sau să treceți în alt mod la următorul element al matricei - acest lucru se întâmplă automat cu fiecare iterație a foreach.

A doua opțiune este utilizată atunci când lucrați cu tablouri asociative:

$wine_inventory = matrice (

"merlot" => 15,

"zinfandel" => 17,

„sauvignon” => 32

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

printează „$item_count sticle cu $i rămase
";

În acest caz, rezultatul arată astfel:

Au mai rămas 15 sticle de merlot

Au mai rămas 17 sticle de zinfandel

Au mai rămas 32 de sticle de sauvignon

După cum puteți vedea din exemplele de mai sus, construcția foreach simplifică semnificativ lucrul cu matrice.

Principiul de funcționare al constructului comutator amintește oarecum de dacă - rezultatul obținut din evaluarea expresiei este verificat cu o listă de potriviri potențiale.

Acest lucru este util în special atunci când verificați mai multe valori, deoarece utilizarea unui comutator face programul mai vizual și mai compact. Formatul general al comenzii de comutare este:

comutator (expresie) (

caz (condiție):

caz (condiție):

Condiția care este testată este indicată în paranteze după cuvântul cheie switch. Rezultatul calculului său este comparat secvenţial cu condiţiile din secţiunile de caz. Dacă se găsește o potrivire, blocul secțiunii corespunzătoare este executat. Dacă nu se găsește nicio potrivire, blocul de secțiune implicit opțional este executat.

După cum veți vedea în capitolele următoare, unul dintre cele mai mari puncte forte ale PHP este gestionarea inputurilor utilizatorului. Să presupunem că un program afișează o listă derulantă cu mai multe opțiuni și fiecare linie din listă corespunde unei comenzi care este executată într-un construct de caz separat. Este foarte convenabil să construiți implementarea folosind comanda switch:

$user_input = "retete"; // Comandă selectată de utilizator

comutator ($user_input):

caz(„căutare”):

print "Să facem o căutare!";

caz(„dicționar”):

tipăriți „Ce cuvânt ați dori să căutați?”;

caz ("retete"):

print "Iată o listă de rețete...";

print "Aici este meniul...";

După cum puteți vedea din fragmentul de mai sus, comanda de comutare oferă o organizare clară și vizuală a codului. Variabila specificată în condiția de comutare (în acest exemplu, $user_input) este comparată cu condițiile tuturor secțiunilor de caz ulterioare. Dacă valoarea specificată în secțiunea de caz se potrivește cu valoarea variabilei care este comparată, blocul acestei secțiuni este executat. Comanda break previne verificarea altor secțiuni de caz și încheie execuția construcției de comutare. Dacă niciuna dintre condițiile verificate nu este îndeplinită, secțiunea implicită opțională este activată. Dacă nu există nicio secțiune implicită și nici una dintre condiții nu este adevărată, comanda de comutare pur și simplu se încheie și execuția programului continuă cu următoarea comandă.

Trebuie să rețineți că, dacă nu există o comandă break în secțiunea case (vezi secțiunea următoare), execuția comutatorului continuă cu următoarea comandă până când este întâlnită o comandă break sau se ajunge la sfârșitul instrucțiunii switch. Următorul exemplu demonstrează consecințele lipsei unei comenzi break: $value = 0,4;

comutare($valoare):

print „valoarea este 0,4
";

print „valoarea este 0,6
";

print „valoarea este 0,3
";

print "Nu ai ales o valoare!";

Rezultatul arată astfel:

Absența unei comenzi break a dus la executarea nu numai a comenzii de tipărire în secțiunea în care a fost găsită potrivirea, ci și a comenzii de tipărire în secțiunea următoare. Apoi, comenzile din instrucțiunea switch au fost întrerupte de o comandă switch care urmează celei de-a doua comenzi de tipărire.

Alegerea între comenzile comutatoare și dacă nu are practic niciun efect asupra performanței programului. Decizia de a folosi un design sau altul este mai degrabă o chestiune personală pentru programator.

Comanda break întrerupe imediat execuția instrucțiunii while, for sau switch în care este găsită. Această comandă a fost deja menționată în secțiunea anterioară, dar întreruperea buclei curente nu epuizează capacitățile comenzii break. În general, sintaxa pauzei arată astfel:

Parametrul opțional n specifică numărul de niveluri de constructe de control încheiate de comanda break. De exemplu, dacă o comandă break este imbricată în două comenzi while și break-ul este urmată de numărul 2, ambele bucle ies imediat. Valoarea implicită pentru n este 1; ieșirea la un nivel poate fi indicată fie prin specificarea explicită a 1, fie prin specificarea comenzii break fără un parametru. Rețineți că comanda i f nu este unul dintre constructele de control care pot fi întrerupte de comanda break.



 


Citit:



Cine deține și cum este descifrat canalul TNT Numele canalului TNT

Cine deține și cum este descifrat canalul TNT Numele canalului TNT

În noua sa funcție, va fi responsabil pentru componenta creativă a canalului, producția de conținut și dezvoltarea de noi formate. Viaceslav Dusmukhametov...

Programe pentru recuperarea unei unități flash Cum să verificați dacă o unitate flash este recuperabilă

Programe pentru recuperarea unei unități flash Cum să verificați dacă o unitate flash este recuperabilă

O unitate flash USB nu este cel mai potrivit dispozitiv pentru stocarea permanentă a fișierelor, dar orice se poate întâmpla în viață. Și situații în care date valoroase...

Cum să inserați o altă față într-o fotografie

Cum să inserați o altă față într-o fotografie

O suită de instrumente de editare foto pe care să o alegeți din Fotor este un puternic editor de fotografii online și un instrument de design grafic. Oferă...

Detectarea automată a motorului forumului Toate plăcile alimentate de smf

Detectarea automată a motorului forumului Toate plăcile alimentate de smf

Să începem imediat cu codul scriptului principal: #!/usr/bin/perl # which-forum.pl script # (c) 2010 Alexandr A Alexeev, http://site/ use strict; #...

imagine-alimentare RSS