Spletni PHP krožek

4. teden

Živjo!

Ta teden pa nekaj čisto drugačnega... spoznali bomo pogojne stavke (ang. conditional sentences) in zanke (ang. loops).

Interpretacija kode

Do sedaj se je naša koda izvajala linearno od zgoraj navzdol, če spregledamo bloke funkcij (ki se izvedejo samo ob klicih).

Z uvedbo pogojnih stavkov se bo nek blok kode (koda med dvema zavitima oklepajema - { in }) izvedel samo, če bo zadoščeno nekemu pogoju,

z uvedbo zank pa se bo nek blok kode izvajal (ponavljal) toliko časa, dokler bo zadoščeno nekemu pogoju.

Dokler se izvajanje zanke ne konča, se program ne bo izvajal naprej.

Primeri s psevdokodo (s psevdokodo zgolj "idejno" opišemo izvorno kodo - ne uporabimo pravih ukazov):

Zaporedno izvajanje ukazov:

a   /* ukazi a, b in c
b      se izvedejo enkrat;
c      po vrsti: a, nato b in na koncu c */

Pogojni stavek, kjer se preverja resničnost enega pogoja:

če (pogoj) {
    d           // ukaz d se izvede samo, če je pogoj resničen (true)
}

Pogojni stavek, kjer se preverja lažnost enega pogoja:

če (!pogoj) {
    e           /* ker je pred pogojem klicaj (!), se ukaz e izvede samo,
}               če je pogoj neresničen (false) */

Pogojni stavek, kjer se preverja resničnost dveh pogojev:

če (pogoj1 IN pogoj2) {
    f           // ukaz f se izvede samo, če sta pogoja pogoj1 in pogoj2 hkrati resnična
}

Dva primera zank:

štej (od 1 do 100, povečuj po 1) {
    izpiši trenutno število                // izpiše števila 1,2,3,4,5,...,98,99,100
}
ponavljaj dokler (pogoj3) {
    g           // ukaz g se bo izvajal toliko časa, dokler je zadoščeno pogoju pogoj3
}

Pogoji

Pogoji so lahko večih vrst, najpreprostejši so primerjalni pogoji, npr.:

Primerjava številčnih vrednosti

$a < 5 (število, ki je shranjeno v spremenljivki $a je (naj bo / mora biti) manjše od 5)
$a > 5 (število $a je večje od 5)

$b == 1 (število $b je enako 1 (obvezno dva enačaja!))
$b != 1 (število $b ni enako 1)

$c >= $d (število $c je večje ali enako številu $d)
$c <= $d (število $c je manjše ali enako številu $d)

Primerjava nizov, boolean in objektov

$ime == "Marko" (v spremenljivki $ime je shranjen niz "Marko")
$ime != "Marko" (v spremenljivki $ime ni shranjen niz "Marko")

$dezuje == true
ali
$dezuje ($dezuje je spremenljivka tipa boolean in je resnična)
$dezuje == false
ali
!$dezuje ($dezuje ni resnična)

$objekt1 === $objekt2 (v obeh spremenljivkah je objekt istega tipa - trojni enačaj)
$objekt1 !== $objekt2 ($objekt1 in $objekt2 nista istega tipa)

Združevanje pogojev

Poljubno število pogojev lahko združimo z naslednjimi oznakami:

AND oz. && (vsi pogoji morajo biti hkrati resnični, da je resnična celota)
Primera:
$a < 10 AND $a > 5 (število $a je med 5 in 10)
$a < 10 && $a > 5 (krajši zapis)

OR oz. || (vsaj en pogoj mora biti resničen, da je resnična celota)
Primera:
$ime == "Marko" OR $ime == "Zasekamož" OR $ime == "Dodo"
(niz v spremenljivki $ime je lahko "Marko", "Zasekamož" ali "Dodo")
$ime == "Marko" || $ime == "Zasekamož" || $ime == "Dodo" (krajši zapis)

XOR (da je resnična celota, mora biti resničen natanko en pogoj)
Primer:
$dezuje == true XOR $soncno == true (lahko dežuje ali pa je sončno, ne more pa deževati pri sončnem vremenu ali pa, da ne bi niti deževalo niti bilo sončno)

Pogojni stavek if

Ima osnovno obliko

if (pogoj) {
    // ukazi, ki se izvedejo, če je pogoj resničen
}

pri čemer namesto pogoj zapišemo nek pogoj ali več združenih pogojev.

Primera:

$starost = 20;

if ($starost >= 18) {
    print "Lahko voziš avto";
}

V tem primeru preverjamo, če je številčna vrednost spremenljivke $starost večja ali enaka 18;
namesto $starost >= 18 bi lahko napisali tudi $starost > 17, ker operiramo samo s celimi števili.

$sit = true;
$zejen = false;

if ($sit && !$zejen) {
    print "Super!";
}

V tem primeru preverjamo resničnost spremenljivke $sit in neresničnost spremenljivke $zejen.


Morda bi želeli poleg prvega bloka napisati tudi blok kode, ki se izvede, če pogoj ni resničen, zato osnovno obliko pogojnega stavka if razširimo z ukazom else, tako da dobimo:

if (pogoj) {
    // ukazi, ki se izvedejo, če je pogoj resničen
} else {
    // ukazi, ki se izvedejo, če pogoj ni resničen
}

Primer:

$starost = 20;

if ($starost >= 18) {
    print "Lahko voziš avto";      // A
} else {
    print "Nisi še polnoleten";    // B
}
Če bo v spremenljivki $starost vrednost, večja ali enaka 18, se bo izvedel blok kode, označen z A, drugače (če bo v spremenljivki $starost vrednost, manjša od 18) pa se bo izvedel blok kode, označen z B.

Primer programa za prijavo v nek zaščiten sistem:

<form method="post">
Uporabnisko ime: <input type="text" name="username"/><br />
Geslo: <input type="password" name="password"/><br />
<input type="submit" name="akcija" value="Prijava"/>
</form>

<?php

if ($_POST['akcija'] == "Prijava") {
    if ($_POST['username'] == "Marko" && md5($_POST['password']) == "098f6bcd4621d373cade4e832627b4f6") {
        print "<b>Prijava je bila uspesna!<b>";
    } else {
        print "<b>Napacno uporabnisko ime ali geslo!<b>";
    }
}

?>

Analiza kode:

1. Uporabili smo dva pogojna stavka, enega v drugem (zunanji preveri, če smo kliknili na gumb Prijava, notranji pa v primeru, da smo, preveri pravilnost uporabniškega imena (ki mora biti Marko) in gesla (ki mora biti test, vendar je zaradi varnosti kodiran z md5, da se ga iz izvorne kode ne da razbrati))

2. Pogoj znotraj 2. pogojnega stavka je sestavljen iz primerjave vrednosti spremenljivke $_POST['username'] in primerjave vrednosti, ki jo vrne funkcija md5(), če ji kot argument podamo spremenljivko $_POST['password'].

3. Če kot uporabniško ime napišemo Marko in za geslo test ter nato kliknemo na gumb Prijava, nam sistem na zaslon izpiše "Prijava je bila uspešna!", v nasprotnem primeru (del else) pa nam izpiše "Napačno uporabniško ime ali geslo!".

else if

Včasih želimo preveriti več možnosti stanja pogoja - to lahko storimo z ukazom else if, ki ga dodamo v našo osnovno obliko pogojnega stavka if:

if (pogoj1) {
    // ukazi, ki se izvedejo, če je pogoj1 resničen
} else if (pogoj2) {
    // ukazi, ki se izvedejo, če pogoj1 ni resničen, je pa resničen pogoj2
} else if (pogoj3) {
   
// ukazi, ki se izvedejo, če pogoj1 in pogoj2 nista resnična, je pa resničen pogoj3
} else {
    // ukazi, ki se izvedejo, če pogoj1, pogoj2 in pogoj3 niso resnični
}

else if lahko v pogojnem stavku uporabimo poljubno mnogokrat

Primer programčka, ki nam pokaže slikice z željenim številom žiraf :)

<form method="get">
Stevilo ziraf: <input type="text" name="stevilo"/><br />
<input type="submit" name="akcija" value="Poslji"/>
</form>

<?php

if ($_GET['akcija'] == "Poslji") {

    $stevilo = intval($_GET['stevilo']);

    if ($stevilo < 0) {
        $stevilo = 0;
    }

    if ($stevilo == 0) {
        print "<img src='http://www2.shrani.si/files/0552001.jpg' alt='Nic ziraf'/>";
    } else if ($stevilo == 1) {
        print "<img src='http://www2.shrani.si/files/1552002.jpg' alt='Ena zirafa'/>";
    } else if ($stevilo == 2) {
        print "<img src='http://www2.shrani.si/files/2552003.jpg' alt='Dve zirafi'/>";
    } else if ($stevilo == 3) {
        print "<img src='http://www2.shrani.si/files/3552029.jpg' alt='Tri zirafe'/>";
    } else {
        print "<img src='http://www2.shrani.si/files/veliko552004.jpg' alt='Veliko ziraf'/>";
    }

}

?>

Analiza kode:

1. Tokrat smo za spremembo namesto metode post uporabili metodo get.

2. Z zunanjim if stavkom (ki se nahaja v 8. vrstici) preverimo, če je uporabnik kliknil na gumb.

3. Število žiraf v 10. vrstici iz spremenljivke $_GET['stevilo'] shranimo v $stevilo in ga pri tem pretvorimo v celo število (če bi uporabnik v okence zapisal kakšno besedo, bi bila njegova številčna vrednost nato enaka 0.) - s tem se prepričamo, da bomo res operirali s števili.

4. Z 12. - 14. vrstico negativna števila spremenimo v 0.

5. 16. - 26. vrstica: najprej preverimo, če je število morda 0 in izpišemo HTML kodo za prikaz slike brez žiraf. V nasprotnem primeru imamo pripravljene slikice za 1, 2 ali 3 žirafe ter sliko z veliko žirafami, ki se prikaže, če je uporabnik napisal število, večje od 3.

Pogojni stavek switch

Ta stavek je v bistvu nadomestek strukture else if. Z njim primerjamo vrednost neke spremenljivke in za različne primere izvršimo določeno kodo. Osnovna oblika je:

switch(spremenljivka) {
    case vrednost1: // koda, ki se izvrši, če je vrednost spremenljivke enaka vrednost1
    break;
    case vrednost2: // koda, ki se izvrši, če je vrednost spremenljivke enaka vrednost2
    break;

    // ...

    case vrednostN: // koda, ki se izvrši, če je vrednost spremenljivke enaka vrednostN
    break;

    default: /* koda, ki se izvrši, če vrednost spremenljivke ni enaka vrednost1, vrednost2, ...
             , ... , vrednostN */
}

V glavi stavka navedemo spremenljivko, katere vrednosti želimo primerjati, znotraj pa imamo poljubno število elementov case, kjer navedemo možne vrednosti, za dvopičji pa pride koda, ki naj se izvrši v tistem primeru. Za vsakim elementom case pride še ukaz break. Poseben ukaz je default, ki igra enako vlogo kot else v if stavku - koda, ki je napisana "pod" njim, se izvrši v primeru, da so vsi prejšnji kriteriji odpovedali.

Praktičen primer uporabe:

switch($_GET['ime']) {
    case "Marko": print "Kako lepo ime!";
                  break;
    case "Zasekamož": print "Tako je pa ime mojemu hrčku :)";
                  break;
    default: print "Tebi ni ime niti Marko niti Zasekamož :P";
}

Če stran pokličemo z ....php?ime=Marko, se izpiše "Kako lepo ime!", pri ....php?ime=Zasekamož se izpiše "Tako je pa ime mojemu hrčku :)", drugače pa se izpiše "Tebi ni ime niti Marko niti Zasekamož :P".

Zanka for

Poleg pogojnih stavkov, s katerimi spreminjamo potek izvajanja programa, včasih želimo kakšno stvar izvesti večkrat (recimo 10x) zapored. Najpreprostejši primer bi bil izpis števil od 1 do 100. Le-ta bi seveda lahko izpisali ročno, vendar je veliko preprosteje, če uporabimo for zanko. Osnovna oblika zanke:

for (inicializacija števca; pogoj; sprememba števca) {
    // koda
}   

V for zanki operiramo s števcem, običajno ga označimo z $i in z njim štejemo v celih številih. Deli glave for zanke so:

inicializacija števca - tukaj števec $i nastavimo na začetno vrednost, recimo na 1: $i = 1
;
pogoj - s pogojem določimo število ponovitev - zanka se izvaja, dokler je pogoj resničen, npr. štejmo, dokler je $i manjši ali enak 100 : $i <= 100
;
sprememba števca - ni vedno nujno, da štejemo po 1 navzgor ali navzdol, zato imamo možnost določiti ukaz za spremembo števca - v našem primeru bomo kar pustili $i = $i + 1 (naslednja vrednost je za 1 večja od prejšnje)

Izpis števil od 1 do 100:

for ($i = 1; $i <= 100; $i = $i + 1) {
    print $i . "<br />";
}

Znotraj same for zanke lahko vedno dostopamo do trenutne vrednosti števca, ki jo v našem primeru uporabimo za izpis števil od 1 do 100, ni pa nujno, da nas sama vrednost števca vedno zanima.

Namesto $i = $i + 1 običajno uporabljamo krajšo obliko: $i++ (enako za $i = $i -1 uporabljamo $i--)

Primer izpisa besede, ki jo določimo prek metode get, kjer hkrati tudi določimo število ponovitev (iteracij):

for ($i = 0; $i < intval($_GET['koliko']); $i++) {
    print $_GET['beseda'] . "<br />";
}

Če to skripto pokličemo z ukazom test.php?beseda=Marko&koliko=15, se bo na zaslonu beseda Marko izpisala 15x.

Zanki while in do ... while

Včasih niti ne želimo operirati s števcem, ampak samo želimo ponavljati nek del kode, dokler je zadoščeno nekemu pogoju, zato lahko uporabimo zanko while. Ta zanka ima osnovno obliko

while (pogoj) {
    // koda
}

Koda v bloku se izvaja, dokler je pogoj resničen (resničnost pogoja se preverja na začetku vsake ponovitve).

Če je pogoj ob začetku izvajanja zanke neresničen, se koda v zanki ne bo izvedla.

Podobna zanka je tudi zanka do ... while:

do {
    // koda
} while (pogoj); // bodite pozorni na podpičje!

Koda v bloku se izvaja, dokler je pogoj resničen in se izvede najmanj enkrat (tudi, če je pogoj ob začetku izvajanja zanke neresničen).

Primer uporabe (ki ga bomo spoznali v naslednjih tednih): branje iz datoteke - z zanko while beremo, dokler nam sistem ne javi oznake za konec datoteke (EOF).

Praktičen primer uporabe zanke while - generiranje 20-mestnega naključnega gesla:

$crke = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","r","s","t","u","v","z");
$geslo = "";

while (strlen($geslo) < 20) {
    $geslo = $geslo . $crke[rand(0,21)];
}

print $geslo;

Analiza po vrsticah:

1. vrstica: ustvarimo 1-dimenzionalno polje $crke z 22 črkami (slovenska abeceda brez šumnikov)
2. vrstica: spremenljivki $geslo nastavimo začetno vrednost na prazno
4. - 6. vrstica: v zanki while s funkcijo strlen() preverjamo trenutno dolžino niza z geslom in jo izvajamo, dokler le-to ni dolgo 20 znakov. Ob vsaki iteraciji geslu dodamo en znak iz polja $crke, da pa bi bil le-ta naključen, s funkcijo rand() vsakič določimo naključni ključ iz polja, ki ima lahko vrednost od 0 do 21 (ker začnemo šteti pri 0)
8. vrstica: dobljeno geslo izpišemo na zaslon.

Kaj smo se naučili

Sedaj znamo pisati (sestavljene) pogoje, uporabljati stavke if, switch, while in do ... while, s čimer smo zelo razširli svoja programerska obzorja. Te strukture so osnova vseh modernih objektno usmerjenih programskih jezikov. Veselo reševanje domače naloge!