Operatii cu variabile. Structuri repetitive
O structura repetitiva este o secventa de cod ce permite realizarea repetata a aceleiasi operatii de un anumit numar de ori. O structura repetitiva este definita de 2 elemente: operatia care este executata si conditia de oprire a executiei. In unele cazuri se cunoaste si numarul de executii (sau iteratii).
Iata cateva aplicatii care implementeaza anumite tipuri de structuri in PHP:
Structura repetitiva for 7
Se foloseste atunci cand se cunoaste dinainte numarul de repetitii (numarul de pasi ce se vor executa). Are urmatoarea sintaxa:
for( [instructiune1] ; [conditie] ; [instructiune2] ) { [instructiune3] }
unde:
- instructiune1 este o instructiune de executat la inceput
- conditie este o expresie care daca este evaluata ca adevarata va determina repetarea ciclului - este denumita generic conditia de repetare
- instructiune2 se va executa la fiecare pas al repetarii
- instructiune3 reprezinta operatia efectiva care se repeta in cadrul FOR-ului
In general, [instructiune1] este o expresie de initializare de forma $i = 1, conditia de repetare este de forma $i <= numarul de pasi si [instructiune2] este o expresie de incrementare $i++.
for( $i = 1; $i <= 10; $i++ ) {
echo $i; // instructiune3
}
In limbaj natural, intructiunea se traduce prin "plecand de la $i = 1, executa operatia si creste-l pe $i cu o unitate; apoi repeta totul atat timp cat $i <= 10
De retinut: instructiunea din cadrul for-ului se executa doar daca expresia (conditia) este adevarata, deci pot exista situatii cand expresia este falsa si [instructiune3] nu se executa niciodata. Exemplu:
for( $i = 0; $i > 10; $i++ ) {
echo 'Aceasta instructiune nu se executa niciodata, pentru ca valoarea ' .
'initiala a lui $i nu este mai mare decat 10';
}
Structura repetitiva while 3
Instructiunea while este folosita atunci cand nu se cunoaste dinainte numarul de executii. Are o forma mai intuitiva decat for si multe persoane o considera mai usor de folosit. Diferenta dintre while si for este aceea ca prima este mai generala si mai flexibila. Se poate chiar afirma ca for este o situatie particulara a unei structuri while. Sintaxa este urmatoarea:
while( [conditie] ) { [instructiune] }
Este probabil usor de inteles ca [instructiune] se executa atata timp cat [conditie] este adevarata. La fel ca si la for, exista posibilitatea ca instructiunea sa nu fie executata niciodata.
Mai jos este un exemplu de structura repetitiva while care are acelasi rezultat ca secventa de cod de mai sus ce foloseste for. Se poate observa ca in cazul structurii while conditia are la baza, de multe ori, o variabila initializata in exterior si modificata in interior. In cazul de mai jos, $i este modificata la fiecare executie, pana cand, la un moment dat, va fi mai mare decat 10 ceea ce va determina iesirea din bucla repetitiva.
$i = 0;
while( $i <= 10 ) {
echo $i;
$i++; // la fiecare pas $i creste cu o unitate
}
De retinut: este de datoria programatorului sa includa in blocul din structura repetitiva si codul necesar iesirii din bucla. Daca acest lucru nu se realizeaza, codul se va executa la nesfarsit. Exemplu:
$continua = true;
while( $continua == true ) {
echo 'La nesfarsit', '
';
}
echo 'Aici nu se mai ajunge';
Varianta corecta a exemplului de mai sus este urmatoarea:
$continua = true;
while( $continua == true ) {
echo 'La nesfarsit', '
';
$continua = false; # modific variabila de testare a conditiei
}
echo 'Acum se ajunge aici';
<?php
$continua = true;
while( $continua == true ) {
echo 'La nesfarsit', '<br>';
break;
}
echo 'Aici nu se mai ajunge';
?>
Intrebare pe baza codului dat ca exemplu pentru executia infinita. Daca "scap" in executie scriptul, cum il pot opri/depana?
$continua = true;
while( $continua == true ) {
echo 'La nesfarsit', '<br>';
}
echo 'Aici nu se mai ajunge';
Presupunand ca scriptul e pus pe un server web si accesat in browser, cat timp pagina se incarca, scriptul va rula la infinit. Il poti opri fortat doar oprind incarcarea paginii, sau il va opri automat interpretorul PHP dupa o perioada de timp (de obicei 30sec).
In orice caz, este o greseala sa ai un script infinit. Structurile repetitive trebuie sa aiba intotdeauna o modalitate de oprire.
Adauga un comentariu la aceasta sectiune.
Structura repetitiva do... while 9
O alta structura repetitiva este do... while. Diferenta fata de while este ca verificarea de face la final, dupa ce se executa cel putin o data secventa de cod. O traducere in cuvintele noastre ar fi: "executa secventa si, cat timp conditia este adevarata, repet-o".
Structura do... while are urmatoarea forma:
$i = 0;
do {
echo $i;
$i++;
} while( $i <= 10 );
Se poate observa o asemanare foarte mare cu structura while, singura diferenta fiind pozitionarea conditiei fata de codul executat, ceea ce asigura minim o executie a codului, chiar daca evaluarea conditiei determina iesirea din bucla. Astfel, daca la for si while este posibil ca secventa de cod din cadrul structurii repetitive sa nu se execute niciodata, in cazul do... while bucla va avea cel putin o executie.
In exemplul de mai jos codul se va executa o data, chiar daca $i nu corespunde conditiei. Verificarea lui se va face oricum dupa executarea blocului din interiorul structurii. Evaluarea conditiei va determina iesirea din structura repetitiva, fara o alta repetare a executiei.
$i = 11;
do {
echo $i;
$i++;
} while( $i <= 10 );
Structura do... while este destul de rar folosita in practica, dar este utila pentru situatiile in care este nevoie de minim o executie a codului.
O aplicatie practica de folosire a structurii repetitive do... while este prezentata mai jos. Secventa de cod de mai jos afiseaza prima aparitie a valorii 0 intr-un sir de numere cu lungimea de minim 1.
/* avem un vector cu un numar necunoscut de valori; vrem sa cautam valoarea 0
* folosind o structura repetitiva. intrucat vectorul are minim 1 element, putem
* folosi structura do... while, care va face cel putin o repetare */
$vector = array( 3, 4, 5, 1, 2, 9, 76, 42, 2, 9, 6, 0, 4, 1, 10 );
# operatia: se verifica daca elementul curent al vectorului este 0
# conditia de repetare: elementul curent nu este 0 si nu s-a ajuns la finalul vectorului
# nota: in acest caz putem afla numarul de elemente al vectorului, in functie de care
# putem defini numarul maxim de repetari, deci putem folosi si structura for
# alternativ putem folosi si structura while
$pozitie = 0; // plecam de la primul element
// parcurgem vectorul pana cand ajungem la final sau gasim valoarea 0
do {
// presupun mai intai ca elementul de la repetarea curenta este 0
$gasit = true;
// verific daca elementul curent (initial primul element) este diferit de 0
// cu alte cuvinte, deocamdata nu am gasit ce caut, deci merg mai departe
if( $vector[ $pozitie ] != 0 ) {
$gasit = false;
}
// trec la pozitia urmatoare pentru verificare
$pozitie++;
} while ( !$gasit && $pozitie < count( $vector ) );
if( $gasit == true ) print "Am gasit 0 pe pozitia $pozitie";
else print "Nu am gasit 0 in vectorul asta";
/* afiseaza
Am gasit 0 pe pozitia 11
*/
Am o nelamurire aici: while ( !$gasit && $pozitie < count( $vector ) )
Cum s-ar traduce asta? cat timp $gasit este fals si $pozitie mai mic decat lungimea sirului?
si aici
if( $gasit )- inseamna acelasi lucru cu if ($gasit=true)?
Multumesc
Cu alte cuvinte:
while ( !$gasit && $pozitie < count( $vector ) )s-ar mai putea sicrie si
while ( $gasit=false && $pozitie < count( $vector ) )?
Am folosit alt sir
$sir = array (1,5,7,3,0,8,5,6,9,0,2,4)
si aplicand secventa mi-a tiparit doar ca exista 0 pe pozitia 4, dar m-ai am unul pe pozitia 9. De ce nu mi l-a gasit si pe acela?
Salut Daniel, afirmatiile tale legate de $gasit sunt corecte.
if($gasit) este echivalent cu if($gasit == true) iar if(!$gasit) este echivalent cu if($gasit == false). [Nota: atentie la == si =, sunt diferite!]
Acest lucru este posibil deoarece variabila $gasit in sine poate fi evaluata la valoarea true sau false, cum de altfel si comparatia $gasit == true poate fi evaluata la o valoare boolean. Poti folosi oricare varianta ti se pare mai usor de urmarit si inteles.
Iar legat de !$gasit, acea expresie contine operatorul de negatie ! care schimba valoarea variabilei (din true in false si invers). Se poate traduce cu "nu este $gasit" sau "$gasit este fals", exact cum ai spus si tu.
Legat de exemplul cu do...while, codul va cauta primul element cu valoarea 0 apoi se va opri. Asa cum este spus si in comentariul de la inceputul codului, operatia se executa cat timp nu s-a gasit valoarea 0 si nu s-a ajuns la finalul sirului: while ( !$gasit && $pozitie < count( $vector ) );
Daca vrei sa afiseze toate valorile de 0 trebuie sa modifici conditia de continuare a executiei si sa lasi doar verificarea pozitiei: while ( $pozitie < count( $vector ) ); Astfel se vor parcurge toate elementele sirului si nu se va mai opri cand $gasit este true. Mai trebuie sa muti ultimul if in interiorul structurii repetitive (ca sa afizeze toate pozitiile): if( $gasit ) print "Am gasit 0 pe pozitia $pozitie";
Voi modifica putin comentariile din cod ca sa fie mai clar.
Multumesc, pentru raspuns, acum mi-e clar. legat de exemplul meu cu acel $sir, am incercat sa va urmez sfatulsi am introdus if-ul ultim in bucla, dar am avut probleme cu iesirea din bucla pentru ca imi rula la nesfarsit "Nu am gasit 0 in vectorul asta,Nu am gasit 0 in vectorul asta,Nu am gasit 0 in vectorul asta, Am gasit 0 in pozitia4, am gasit 0 in pozitia4......am gasit 0 in pozitia4...si tot asa pana la infinit, la zero de la pozitia 9 nu imi mai ajungea. Insa am reusit totusi sa fac cu for:
<?php
$sir = array (1, 5, 7, 3, 0, 8, 5, 6, 9, 0, 2, 4);
for ($pozitie=0; $pozitie<=11; $pozitie++) {
if ($sir[$pozitie]==0) print "Am gasit 0 pe pozitie $pozitie";}
?>
unde anume trebuia sa introduc acel if in structura repetitiva pentru a reusi si cu do...while? eu l-am introdus imediat dupa ce am inchis blocul de instructiuni al primului if.. Adica chiar inainte sa inchid blocul de instructiuni al lui do si inainte de conditia de la while
Era bine pus chiar inainte de terminarea blocului do { ... }. Ar mai fi trebuit stearsa linia cu else sa nu afiseze mesajul "Nu am gasit..." pentru elementele diferite de 0. Sau modificat mesajul in unul mai concludent :)
Cat despre repetarea la infinit, da, codul nu se comporta cum trebuie cand era eliminata expresia !$gasit din conditia de la final. Asta din cauza ca incrementarea pozitiei ($pozitie++) se realiza doar la anumiti pasi (in cadrul if-ului), ceea ce era incorect.
Am modificat exemplul astfel incat instructiunea $pozitie++ sa se execute independent de alte prelucrari din blocul de instructiuni. Acum daca mai faci o data modificarile tale pe noul exemplu ar trebui sa fie totul OK.
Felicitari si pentru adaptarea exemplului la varianta cu for. Este corecta si functionala (desi as modifica 11 cu functia count($sir) pentru flexibilitate).
Multumesc pentru raspuns si pentru felicitari :). am incercat acum modelul urmator:
<?php
$sir = array (1, 5, 7, 3, 0, 8, 5, 6, 9, 0, 2, 4);
$pozitie=0;
do { $gasit=true;
if ($sir [$pozitie] !=0) { $gasit=false;
}
$pozitie++;
if ($gasit==true) echo "Am gasit 0 pe pozitia $pozitie", "<br/>";
} while ( $pozitie<count ($sir));
?>
afiseaza:Am gasit 0 pe pozitia 5
Am gasit 0 pe pozitia 10.
Acum, intr-o situatie normala, intradevar cei doi de zero se afla pe pozitiile 5 si 10 in sir. Dar avand in vedere ca intr-un sir prima pozitie este pozitia 0, nu ar fi trebuit sa imi afiseze 0 in pozitiile 4 si 9, la fel cum mi-a afisat folosind exemplul cu for?
Ei bine, este corect ce se afiseaza pentru ca mai intai creste variabila $pozitie (prin $pozitie++) chiar inainte sa se afiseze mesajul. Din acest motiv iti apar valorile crescute in mesaj. As zice ca e mai corect asa, desi e o chestie interpretabila (eu as intelege ce inseamna pozitia 0, dar o persoana non-tehnica ar crede ca e gresit).
Ca sa afiseze pozitia stricta (incepand de la 0) trebuie mutata instructiunea if inainte de $pozitie++.
Adauga un comentariu la aceasta sectiune.
Iterarea cu foreach 6
PHP ofera o structura repetitiva foarte puternica si des folosita: foreach. Aceasta permite iterarea prin toate elementele unui vector. Pot fi folositi si vectori simpli si asociativi.
Spre deosebire de celelalte instructiuni, pentru foreach nu trebuie specificata explicit o conditie de oprire, fiind de datoria interpretorului PHP sa opreasca iterarea atunci cand s-a ajuns la finalul vectorului.
// parcurgerea unui vector cu foreach
$vector = array( 3, 4, 5, 1, 2, 9 );
// afiseaza: 3 4 5 1 2 9
foreach( $vector as $element) {
print "$element ";
}
// parcurgerea unui vector cu foreach, folosind cheile si valorile
$vector = array( 'a', 'b', 'c', 'd', 'e', 'f' );
// afiseaza: a b c d e f
foreach( $vector as $cheie => $element) {
print "$element ";
}
// afiseaza: 0 1 2 3 4 5
foreach( $vector as $cheie => $element) {
print "$cheie ";
}
// Nota: chiar daca $vector nu este asociativ in mod explicit,
// elementele sale oricum au chei implicite valorile 0, 1, 2, 3 ...
// vector asociativ (definit explicit cu chei)
$zile = array(
'luni' => 'Mo',
'marti' => 'Tu',
'miercuri' => 'We',
'joi' => 'Th',
'vineri' => 'Fr',
'sambata' => 'Sa',
'duminica' => 'Su'
);
// afiseaza Mo Tu We Th Fr Sa Su
foreach( $zile as $eng) {
print "$eng ";
}
// afiseaza si cheia si valoarea intr-un text
foreach( $zile as $rom => $eng) {
print "$eng inseamna $rom
";
}
/* afiseaza
Mo inseamna luni
Tu inseamna marti
We inseamna miercuri
Th inseamna joi
Fr inseamna vineri
Sa inseamna sambata
Su inseamna duminica
*/
Da ca sa afiseze toate zerourile din vector cum se face cu instryctiunea foreach() ???? eu am facut dar asa :
$gasit = false;
$pozitie = 0; // plecam de la primul element
while( !$gasit || !( $pozitie == count( $vector ))) {
if( $vector[ $pozitie ] == 0 ) {
$gasit = true;
print "Am gasit 0 pe pozitia $pozitie <br>";
}
$pozitie++;
cu instr. foreach(), pina ce nu se primeste ))
Cu foreach e si mai simplu:
$gasit = false;
foreach( $vector as $pozitie => $element) {
if( $element == 0 ) {
$gasit = true;
print "Am gasit $element pe pozitia $pozitie <br>";
// aici se poate apela break; daca e nevoie
// sa se intrerupa cautarea dupa primul 0
}
}
if(!$gasit) {
echo "Nu am gasit nici un 0";
}
Intradevar e mai simplu
Buna. pentru inceput am o nelamurire legata de variabilele de aici, $element, $cheie, $rom,$eng. Sunt cumva variabile standard? nu trebuiesc declarate sau initializate cumva? In sensul ca apar acolo si nu stiu de unde sa le iau...
Acele variabile vor fi definite de PHP si vor lua valorile elementelor din vector, pe rand.
Poti folosi orice nume de variabila, iar interpretorul de PHP se va asigura ca in interiorul blocului foreach acea variabila va fi definita si initializata cu valoarea elementului curent din momentul parcurgerii.
De ex.
foreach( $vector as $element) {
print "$element ";
}
In interiorul blocului variabila $element va fi initializata cu primul element din sirul $vector (la prima iteratie), apoi cu al doilea element (la a doua iteratie), s.a.m.d. pana cand variabila $element va lua pe rand toate valorile din $vector. Astfel, cate elemente are vectorul, atatea repetari se vor executa (si tot atatea valori va avea variabila $element).
Similar se intampla si in varianta foreach( $vector as $cheie => $element), cu mentiunea ca variabila $element va prelua valoarea elementelor din vector (conform explicatiei de mai sus), iar variabila $cheie va prelua pozitia elementului din vector.
Adauga un comentariu la aceasta sectiune.
Intreruperea fluxului de executie 0
In toate structurile repetitive prezentate mai sus, executia poate fi intrerupta, partial sau total, folosind instructiunile continue sau break.
continue
Instructiunea continue permite oprirea iteratiei curente a unei structuri repetitive si trecerea imediata la iteratia urmatoare. Folosind continue toate instructiunile din blocul structurii sunt sarite pentru iteratia curenta, iar executia continua cu iteratia urmatoare. Un exemplu:
for($i = 0; $i < 10; $i++) {
/* la toate executiile in care $i <= 5, se va "sari" peste
* instructiunile print; practic, dupa apelul continue,
* executia "trece" la pasul urmator, crescandu-l pe $i */
if( $i <= 5 ) {
continue;
}
print $i;
print "
\n";
}
In exemplul de mai sus avem o structura repetitiva for cu 10 executii (de la 0 la 9). Pentru iteratiile in care $i este sub 6, se va executa instructiunea de control continue, care va sari peste tot ce urmeaza (doua instructiuni print) si va forta trecerea la iteratia urmatoare. Asadar, la finalul executiilor se vor afisa doar numerele de la 6 pana la sfarsit.
De retinut, continue afecteaza doar iteratia curenta; celelalte iteratii se pot executa complet, atat timp cat continue nu este apelata din nou. Nu este nici o diferenta de la o structura repetitiva la alta (for, while, do while) - continue se comporta la fel.
break
Instructiunea break permite intreruperea totala a executiei structurii curente si trecerea la urmatoarea linie de cod. Folosind break toate instructiunile din blocul structurii sunt sarite pentru toate iteratiile (curenta si cele urmatoare). Practic se "iese" fortat din blocul structurii repetitive, iar fluxul de executie continua cu instructiunea de dupa structura repetitiva.
for($i = 0; $i < 10; $i++) {
// cand $i == 2, se va "iesi" din structura
if( $i == 2 ) {
break;
}
print $i;
print "
\n";
}
print "Gata!"; // cand $i == 2 se "sare" direct aici, ignorand celelalte iteratii
Spre deosebire de continue, instructiunea break afecteaza toate iteratiile unei structuri; nici o alta iteratie a blocului structurii nu se mai realizeaza dupa break.
Un apel break are acelasi efect pentru toate structurile repetitive. In plus, instructiunea se poate folosi si in alte structuri de control, cum este switch, avand ca efect "iesirea" din blocul de selectie.
Structuri multiple
In cazul in care exista structuri repetitive multiple, incluse unele in interiorul celorlalte, instructiunile break si continue pot primi ca parametru nivelul structurii pe care o afecteaza. Spre exemplu, daca avem 2 for-uri ca in secventa de cod de mai jos, apelul break 1; se refera la for-ul din interior, pe cand break 2; se refera la primul for (cel cu $i).
$n = 7;
for($i = 0; $i < $n; $i++) {
// la fiecare iteratie a lui $i, avem un alt for
echo 'Iteratia #', $i, ': ';
for($j = 0; $j < $n; $j++) {
if( $i == 4 && $j == 4 ) {
break 2; // se aplica la for-ul mare
}
if( $j >= $n - $i ) {
continue 1; // se aplica la for-ul din mijloc
}
print "$j ";
}
print "\n";
}
De obicei, se recomanda evitarea unor astfel de constructii, intrucat codul devine greu de urmarit si pot sa apara usor probleme. De cele mai multe ori, nici nu va fi nevoie sa apelati continue sau break cu parametru, dar in orice caz, incercati sa evitati pe cat posibil intreruper iteratiilor pe mai multe nivele.
Diferenta dintre break si exit
Intrucat am vorbit despre intreruperea executiei, este posibil sa apara confuzii intre break si exit sau die. Este adevarat ca atat break cat si celelalte intrerup executia secventei de cod, doar ca aceasta intrerupere se realizeaza la niveluri diferite. Astfel, break actioneaza doar la nivelul structurii din este apelat, pe cand exit si die actioneaza la nivelul intregului script PHP.
Instructiunea break va intrerupe executia structurii care o contine, dar va permite continuarea executiei cu alte instructiuni ce urmeaza. Exit sau die nu mai permit nici o alta executie.
for( $i = 0; $i > 10; $i++ ) {
echo 'Aceasta instructiune nu se executa niciodata';
}
la inceput i este 0
dupaia verifica daca e mai mare decat 10 ... daca e mai mare afiseaza : "Aceasta instructiune etc etc etc..."
daca nu... mareste pe i ...
i devine 1 ...
si tot asa pana cand i ajunge peste 10 si o sa tot afiseze aia la infinit
sau nu afiseaza deloc pt k e o executie infinita...
nu stiu exact daca asa e dar o sa verific...imi cer scz dak nu este asa
De fapt este perfect corect. Atunci cand este evaluata conditia, in cazul in care aceasta nu este indeplinita, "for-ul" se opreste. Daca conditia nu este indeplinita de la inceput, nu va fi afisat nimic.
"For-ul" va functiona atata timp cat conditia este indeplinita.
Piny ai expus corect ))) dar e mai usor de lamurit exemplu de sus prin conditia pusa )) $i>10.
Nu $i nu este mai mare ca 10, din acest motiv echo nu va fi aplicat. Daca $i ar avea valoarea 11 atunci ar fi un ciclu infinit si dupa fiecare $i++ va fi aplicat echo in codul infinit.
<?php
function suma($a,$b){
$total=$a+$b;
return $total;
}
for($a=4,$b=5;$a<=10,$b<=10;$a++,$b++){
$total=$a+$b;
echo suma($a,$b).'<br>';
}
return $total;
?>
for( [instructiune] , [conditie], [instructiune2] ) { [instructiune3] }
sa se corecteze cu "instructiune1" sau mai jos cu instructiune :D
conditia nu este adevarata pentru ca variabila a fost declarata initial 0.
asadar nu putem avea $i=o si acelasi $i>10.
for( [instructiune1] , [conditie], [instructiune2] ) { [instructiune3] }
Trebuie inlocuita virgula cu punct si virgula.
Adauga un comentariu la aceasta sectiune.