Az alapoktól...

PHP kezdőknek

PHP kezdőknek

16. lecke - Az MVC szemléletről érthetően

2016. május 26. - Frantique

Divatos a webes programozásban manapság az MVC szemlélet. Majdnem minden ismert és kevésbé ismert keretrendszer ezen módszertan elveit követi.

Az MVC egy rövidítés, az angol Model - View - Controller szavakból ered. Magyarul modell - nézet - vezérlő néven ismerhetik. A lényege az, hogy az adatokat szétválasszuk a megjelenítéstől, így egymástól függetlenül tudjuk tetszés szerint fejleszteni és változtatni mind az adatstruktúrákat, mind a megjelenítés elemeit.

A különböző részek az alábbiak szerint kapcsolódnak egymáshoz a webes alkalmazásokban:

A nézet az aktuálisan megjelenített HTML oldal, a vezérlő a szerveren futó (a mi esetünkben PHP) kód, a modell pedig a konkrétan tárolt adatok, amelyek lehetnek adatbázisban, XML-ben, vagy akár egyszerű szöveges vagy bináris fájlban.

Sematikusan:

(Felhasználó <==> [ HTML oldal ]) <===== HTTP(S) csatorna ====> { [ PHP kód ] <==> [ Adatbázis ] }

A működés egyszerűsítve így nézhet ki:

A felhasználó egy eseményt generál (pl. megnyom egy gombot), az esemény hatására a hozzátartozó adatok (pl. egy űrlap mezői) a HTTP(S) csatornán átutaznak a szerverre (piros rész), ahol a PHP kód egy előre meghatározott forgatókönyv alapján feldolgozza az érkező adatokat (pl. a $_POST változó adatait), és azokat az adatbázisba írja (pl. MySQL adatbázisba), esetleg az adatbázisból kiolvassa a kért adatokat, és visszaküldi azokat a felhasználónak.

A modell és a nézet szétválasztásával csökkenthetjük a programjaink bonyolultságát, valamint az utólagos bővítést és átírást is könnyebbé tehetjük.

 Egy nagyon primitív és egyszerű példán keresztül lássuk a szemléletet a gyakorlatban:

├── controller
│   └── mycontroller.php
├── index.php
├── model
│   └── mymodel.csv
└── view
    ├── myform.html
    └── valasz.html

A mycontroller.php végzi a munkát: a view mappa myform.html-én keresztül begyűjtött adatokat a model mappa mymodel.csv fájljába írja, majd a valasz.html-en keresztül kilistázza a mymodel.csv tartalmát. Az index.php csupán a mycontroller.php befoglalását tartalmazza, semmi egyebet.

 

A házi feladat legyen a fenti séma kidolgozása, a myform kérjen be 2 adatot: egy nevet és egy email címet. A kész megoldást a https://www.facebook.com/virustalanitas/ oldalon lehet elkérni, ha nem sikerül egyedül!

15. lecke - Lépjünk kapcsolatba!

Az igazi programok egyik fontos tulajdonsága az interaktivitás. Amint az emberek is kommunikálnak, úgy a programokkal is kapcsolatba kell lépnünk, hogy hasznos munkát végezzenek. A folyamat leegyszerűsítve:

utasítás -> válasz -> utasítás -> válasz ... 

Az utasítás lehet egy esemény (megnyomunk egy gombot a grafikus felületen, rákattintunk egy linkre), vagy terminálos futtatás esetén egy paraméter értéke. Kezdjük az egyszerűbbel:

Terminálos futtatás

Amennyiben a register_argc_argv be van kapcsolva, elérhetővé válik egy fenntartott változó $argv néven, amely tömb (array) típusú. A futtatás közben megadott paramétereket $argv[1], $argv[2], ... stb. néven érjük el. Az $argv[0] mindig a szkript nevét tartalmazza. Emellett egy $argc nevű változó a megadott paraméterek számát tartalmazza:

php -f pelda.php "első paraméter" "második paraméter"

A pelda.php tartalma legyen ez:

---------------------------

<?php

if ($argc != 3) {      //Ha a paraméterek száma nem 3 (szkript neve + 2 paraméter)
        echo 'Pontosan két paraméter szükséges!'; 
        exit;          // Kilép
}
else {                 // Különben...
        $szkript_neve = $argv[0];
        $elso_parameter = $argv[1];
        $masodik_parameter = $argv[2];
        echo "Szkript: $szkript_neve, #1: $elso_parameter, #2 $masodik_parameter";
        exit;
}

?>

---------------------------

 

A megadott paraméterek értékeivel a programunk dolgozni tud az előzőekben tanultak szerint.

Webszerveres futtatás

Lassan megérkezünk az igazán hasznos területhez: a böngészőben való futtatáshoz. Mielőbb belevágnánk, tisztáznunk kell pár fogalmat: a PHP szerver oldali műveleteket végez, tehát a böngészőben a futása eredményeit láthatjuk, nem ott helyben történnek a PHP-t érintő események. Bármennyire modern legyen egy felület (JavaScript, Ajax-os hívások, stb.), a rendszer továbbra is utasítás -> válasz folyamatokra fog építeni. A böngészők a grafikus felület megjelenítéséhez  HTML-t használnak, amelynek van két speciális interaktivitási módszere: a form és a link. A formban található elemek értékei (szövegmezők, gombok, jelölők, listák) alapesetben POST metóduson keresztül kerülnek a szerverre. A linkek paraméterei pedig GET metódust használnak. 

Szerver oldalon ezen két metódusból származó értékeket fogjuk el, és dolgozzuk fel. Erre két speciális változó áll rendelkezésünkre, amelyek típusa asszociatív tömb:

$_POST['formelem']

és 

$_GET['linkparameter']

Lássunk egy példát! Mentsük el "teszt.php" néven, másoljuk a webszerverünk gyökérkönyvtárába, majd hívjuk meg egy böngészőben, pl. így: "http://szerverem.neve/teszt.php"

---------------------------

 

<?php

$valasz = 'Adj meg bármilyen értéket a fenti szövegmezőbe!';
$linkvalasz = 'Még nem kattintottál a linkre!';

if (isset($_POST['hello'])) {
        $valasz = 'Ezt írtad be:' . $_POST['hello'];
}

if (isset($_GET['linkparameter'])) {
        $linkvalasz = 'A link paramétere: '. $_GET['linkparameter'];
}

echo "<!DOCTYPE html>
<html>
<head><title>Teszt</title></head>
<body>
<form method='post' action='teszt.php'>
<label for='hello'>Szöveg:</hello><input id='hello' type='text' name='hello' value=''><input type='submit' name='do_submit' value='Mehet!'>
</form>
<div>$valasz</div>
<div><a href='teszt.php?linkparameter=valami'>Ez egy link, paraméterrel.</a></div>
<div>$linkvalasz</div>
</body>
</html>";

?>

---------------------------

 FIGYELEM! A fenti példa semmilyen ellenőrzést nem végez a megadott adatokon, csak a működési folyamatot mutatja be. A $_POST és a $_GET meglétét isset() függvénnyel ellenőriztük.

Mindig tervezzük meg alaposan a lépéseket, és ne bízzunk meg vakon semmilyen bejövő adatban! Éles tervezésben az egyik legfontosabb művelet a beérkező adatok ellenőrzése és érvényesítése. A legegyszerűbb és legnaivabb a típusok ellenőrzése (ne engedjünk szöveget ott, ahol számot várunk, stb.), a komolyabbak a különböző adatmanipulációs kísérletek kivédésére irányulnak. Ezekről a későbbiekben tanulunk majd.

 

--------------------------------------------------------------

Feladatok

1. Írjunk egy parancssoros szkriptet, amely 2 paramétert fogad, az első a nevünk, a második az életkorunk! Ellenőrizzük az érkező adatokat, és írjuk ki az eredményt!

2. Írjunk egy webszerveren futó szkriptet, amely a fenti feladat szerint működik!

3. Készítsünk egy webes szkriptet, amely egy alap névjegykártya adatait gyűjti be és jeleníti meg! (Név, telefonszám, emailcím, postai cím)

14. lecke - Függvények

Általános tudnivalók

A függvények olyan jól elkülönülő egységek, amelyek valamilyen célirányos műveletet végeznek. A függvényt többször meghívhatjuk, amolyan célszerszámként is felfogható, amellyel az adott típusú műveletet bármikor elvégezhetjük. A függvényben más függvényeket is meghívhatunk, akár önmagát is!

A függvény szerkezete

A függvényeket function kulcsszóval indítjuk, amely után megadjuk a nevét, zárójelben felsoroljuk a függvény bemeneti értékeit vesszővel elválasztva, majd kapcsos zárójelek között a függvényen belüli kódot. A függvény az elvégzett műveletből származó értékkel visszatér a return parancs segítségével. A függvényen belül szereplő változók lokálisak, így kívülről nem lehet őket elérni (a függvényen kívüli változókat viszont a global utasítással emelhetjük be a függvénybe).

function osszead($elso_szam, $masodik_szam) {
        global $kulso_valtozo_1, $kulso_valtozo_2;

        $eredmeny = $elso_szam + $masodik_szam + $kulso_valtozo_1 + $kulso_valtozo_2;
        return $eredmeny;
}

Lássuk a fenti függvényt működés közben:

--------------------

<?php

$sz1 = 11;
$sz2 = 22;
$sz3 = 33;

$eredmeny = osszead($sz1, $sz2);
echo $eredmeny; 

function osszead($elso_szam, $masodik_szam) {
    global $sz3;                                   // Beemeljük a változót

    $eredmeny = $elso_szam + $masodik_szam + $sz3; // Művelet...
    return $eredmeny;                              // Visszatérünk az eredménnyel
}

?>

--------------------

Felhasználói függvények

Felhasználói függvénynek hívjuk azokat a függvényeket, amelyeket mi magunk hozunk létre a fenti példához hasonlóan. Amire vigyázni kell, hogy a függvényünk elnevezése ne okozzon ütközést se már létező, beépített függvényekkel, se védett kulcsszavakkal. Ezek listáját a mindenkori dokumentációban találjuk meg. A függvény meglétének vizsgálatát a function_exists('fuggveny_neve') beépített függvénnyel végezhetjük el. A visszatérő érték logikai.

 

Beépített függvények

 A beépített függvényeket a PHP telepítés szállítja. Aszerint, hogy milyen modulokkal telepítjük, több-kevesebb beépített függvényt érhetünk el. A teljes dokumentációt a http://php.net oldalon találhatjuk. A modulokat ki-be kapcsolhatjuk a rendszerben, amennyiben modulárisan fordították az általunk használt példányt. Ezen feladatok elvégzése rendszergazdai feladat, több tematikus oldalt is találunk a neten, továbbá például a http://hup.hu oldalon szakemberek is segítenek, ha elakadunk.

Változó függvények

A változó függvény fogalma azt jelenti, hogy ha egy változót zárójelek követnek, akkor a PHP olyan nevű függvényt keres és futtat, mint a változó értéke:

--------------------

<?php
function osszead($elso_szam, $masodik_szam) {
        $eredmeny = $elso_szam + $masodik_szam;
        return $eredmeny;
}

$fuggveny = 'osszead';

echo $fuggveny(12, 23);  // lefuttatja az osszead függvényt

?>

--------------------

 

Anonim függvények

Az anonim függvények név nélküli függvények, az adott létrehozási helyen szokás használni, általában másik függvény visszatérő értékén végzett további műveletekre. 

--------------------

<?php

$szia = function($nevem) {
        echo "Szia $nevem!";
};    // figyeljük meg a pontosvesszőt!

$szia('Béla'); // Kiírja: Szia Béla!
?>

--------------------

 

-----------------------------------------------------------------------------------------------------

Feladatok

1. Hozzunk létre egy függvényt, amely két számot összeszoroz!

2. Hozzunk létre egy függvényt, amely üdvözli a felhasználót napszaknak megfelelően. A függvény bemenete legyen a név és a napszak megnevezése (reggel, napközben, este), a kimenete pedig szöveg. Tipp: használjunk switchet a függvényen belül!

13. lecke - Ciklusokon belül - break, continue, goto

A ciklusosan ismétlődő műveletek hatékonyságát láttuk az előző leckék során. Mi történik olyan esetben, ha valamiért meg kell szakítani a ciklust még mielőtt az természetes módon véget érne, esetleg át kell ugorni a ciklus belsejében levő kód egy részét? Ezekre az esetekre alkalmazhatjuk a break (vele már találkoztunk korábban), a continue és a goto utasításokat. 

A break csak cikluson belül használható, és a for, foreach, while, do .. while és switch szerkezetek futását szakítja meg. Az utasítás számot fogad el argumentumként: ha meg van adva, akkor ez a szám határozza meg, hogy az egymásba ágyazott ciklusokból milyen szintig kell kitörni. Az alábbi példa ezt szemlélteti:

--------------------

<?php
for ($i = 0; $i < 10; $i++) {                     //3. szint       
        for ($j = 0; $j < 10; $j++) {             //2. szint
                for ($z = 0; $z < 100; $z++) {    //1. szint
                        if ($z > 10) {
                                break 2;          //2. szintre tör ki
                        }
                        echo "i: $i, j: $j, z: $z\n";
                }
        }
}
?>

--------------------

A fenti példában látott 2. szintről való kitörés azt jelenti, hogy valójában a $j értéke sose lesz 0-nál nagyobb, mivel minden körben, amikor elkezdődik a ciklus, a benne levő $z változó értéke, amint eléri a 11-et, visszaugrik a 3. szintre. Ezzel együtt az 1. szint $z értékét sose fogjuk 10 fölött látni kiírva.

Argumentum nélkül csak az aktuális ciklusból tör ki a programunk: ezért a break; kifejezés egyenértékűnek tekinthető a break 1; kifejezéssel.

A continue utasítást olyankor használjuk, amikor a ciklusban levő, a contiue utasítás után következő kódrészletet át akarjuk ugrani:

--------------------

<?php
echo "Páros számok listája:\n";
for ($i = 0; $i <= 10; $i++) {
        if (($i % 2) === 1) {   // Ha van maradék, akkor páratlan,
                continue;       // ezért átugorjuk a többi részt.
        }
                echo "$i\n";    // Kiírjuk a páros számot.
}

?>

 

--------------------

A continue utasítás ugyanúgy elfogad szám argumentumot, mint a break - a működése is azonos: a számérték határozza meg a folyatás szintjét.

A goto ismerős lehet a 35+ korosztálynak, akik még aktívan programoztak valamely BASIC nyelvben. A logikája egyszerűnek tűnik: ugorjunk egy adott nevű címkéhez a kódban, amely címkét cimke: formában adunk meg. Van azonban jó pár megkötése a goto utasításnak: nem ugorhatunk ciklusba vagy függvénybe, csak ugyanazon fájlban levő címkére hivatkozhatunk, valamint nem ugorhatunk ki függvényből. A ciklusokból való kiugrási módszerként azonban alkalmazható. A legegyszerűbb példán keresztül szemléltetjük a goto működését:

--------------------

<?php
goto cimke; // >------->----->---+
echo 'Ezt sose fogod látni!'; // | Ezt a részt átugorjuk...
cimke:   // <------<------<------+ Ugrás ide!
echo 'Ezt viszont igen!';
?>

 

--------------------

Ciklusból való kiugrásra példa:

--------------------

<?php
for ($i = 0; $i < 100; $i++) {
        if ($i > 10) {        //Ha meghaladja a 10-et...
        goto cimke;           //ugrás a címkéhez!
        }
        echo "$i\n";
}
cimke:
echo 'Az $i értéke elérte a 10-et!';
?>

--------------------

Figyelem!

A kódban nem csak lefele, hanem visszafele is lehet ugrani, így nem nehéz végtelen ciklust létrehozni:

--------------------

<?php
eleje:
         echo 'Eleje';
         goto vege;
         echo 'Közepe, amit sose írunk ki.';
vege:
         echo 'Vége';
         goto eleje;
?>

--------------------

 

-----------------------------------------------------------------------------------------------------

Feladatok

1. Hozzunk létre egy ciklust, amely elszámol 100-ig, majd break segítségével ugorjunk ki a ciklusból, ha a változó értéke nagyobb, mint 50!

2. Ágyazzunk egymásba 3 ciklust, és próbáljuk ki, mi történik, ha break utasítást használunk argumentummal, majd írjuk át úgy, hogy a helyére continue kerüljön. Mit tapasztaltunk?

3. Goto segítségével próbáljuk ki a címkékhez ugrást tetszőleges kódon.

 

12. lecke - Vezérlő szerkezetek - switch választó

Vannak esetek, amikor egy változó értékének megfelelően több lehetséges folytatási útvonalunk van. Másképp fogalmazva, egyfajta "forgalomirányító" szerkezetet kell igénybe vegyünk. Erre ott van az if .. else if .. else szerkezet, azonban előfordul, hogy sok lehetséges leágazásunk van. Ilyenkor szebb, átláthatóbb és kényelmesebb a switch szerkezetet használni. A logikája a következő: válasszunk (switch)  esetágat a felsorolt lehetséges értékek (case) szerint (vagyis a case ágon levő mondat értéke TRUE). A szerkezete így néz ki:

switch (érték) {
        case első_megfelelés
                első_esemény; break;
        case második_megfelelés:
                második_esemény; break;
        default:
                alapesemény; break;
}

Megjegyzés

Az esetágak (case) üresek is lehetnek: ebben az esetben az ellenőrzést a következő ágon folytatjuk. Nem szükséges alapesetet (default) létrehozni, ennek hiányában a switch eredmény nélkül ér véget. Tartsuk szem előtt, hogy a switch nem ellenőriz azonosságot!

Lássunk egy konkrét példát! Vizsgáljuk meg, hogy a kiinduló $honap string változóban található valamely hónap neve milyen évszakban található!

--------------------

<?php
$honap = 'február';

switch ($honap) {
        case 'december':
        case 'január':
        case 'február':
                echo "$honap - tél"; break;
        case 'március':
        case 'április':
        case 'május':
                echo "$honap - tavasz"; break;
        case 'június':
        case 'július':
        case 'augusztus':
                echo "$honap - nyár"; break;
        case 'szeptember':
        case 'október':
        case 'november':
                echo "$honap - ősz"; break;
        default:
                echo 'Érvényes hónapot adjon meg!'; break;

}

?>

--------------------

A fenti példában láthatjuk az üres leágazások logikáját és létjogosultságát, valamint egy alapszintű hibakezelést is becsempésztünk a default ágra: amennyiben nem hónapot adott meg, a programunk figyelmeztet rá. 

A case ágak akár függvényeket is ki tudnak értékelni. Kicsit előreszaladva, a fenti példa így oldható meg tömbökkel és in_array() függvénnyel (az in_array() függvény azt vizsgálja, hogy egy érték benne van-e egy adott tömbben. A felépítése: bool  in_array($érték, $tömb [, bool $azonossagi_vizsgalat = FALSE]) A visszatérő értéke logikai (IGAZ vagy HAMIS), a szögletes zárójelben levő rész elhagyható: ebben az esetben nincs típusazonossági vizsgálat.)

--------------------

<?php
$honap = 'szeptember';
$tel = array('december', 'január', 'február');
$tavasz = array('március', 'április', 'május');
$nyar = array('június', 'július', 'augusztus');
$osz = array('szeptember','október','november');

switch ($honap) {
        case in_array($honap, $tel):
                echo "$honap - tél"; break;
        case in_array($honap, $tavasz):
                echo "$honap - tavasz"; break;
        case in_array($honap, $nyar):
                echo "$honap - nyár"; break;
        case in_array($honap, $osz):
                echo "$honap - ősz"; break;
        default:
                echo "Érvényes hónapot adjon meg!"; break;
}

?>

--------------------

Az átirat az olvashatóság mellett tömörebb is lett, és amint láthatjuk, az eredmény ugyanaz. Melyik változatot válasszuk akkor? Erre is azt kell mondanunk, hogy azt, amelyik a projektünkbe jobban beleillik: mivel a második változat összesen öt változót hoz létre, picit memóriaigényesebb, mint az első, ahol csak egy változónk van, valamint a második változaton minden egyes leágazáson még külön függvényt kell meghívnunk ahelyett, hogy helyben végeznénk a műveletet, tehát processzorigényesebb is. (A mérések alapján (strace -c -Ttt), átlagolva az első változat 0.000016 másodpercig, míg a második 0.000036 másodpercig futott - 10.000 mérést végeztünk. Ez nem reprezentatív, de jól mutatja a leheletnyi különbséget a két megoldás között.)

-----------------------------------------------------------------------------------------------------

 

Feladatok

1. Egy csoportban tíz ember van: 3 szőke, 3 barna, 3 fekete és 1 vörös. A szőkék a kávét, a barnák a teát, a feketék a vizet, a vörös meg a bort szeretik. Ha mindegyiknek egyedi neve van, vizsgáljuk meg,  hogy mit iszik egy tetszőlegesen kiválasztott egyén.

2. Írjunk egy programot, amely kiírja, hogy egy tetszőlegesen választott hónap hány napot tartalmaz. Tipp: csoportosítsunk!

3. A budapesti irányítószámok 1-gyel kezdődnek, és a 2. és 3. szám a kerületet jelöli. (Pl. 1064 - Budapest, VI. kerület) Ha tudjuk, hogy 23 kerület van, vizsgáljuk meg, hogy egy tetszőleges, 4 számjegyű irányítószám budapesti? Ha igen, írjuk ki  a kerületet, ha nem, figyelmeztessük a felhasználót a hibáról!

11. lecke - Vezérlő szerkezetek - foreach ciklus

A tömbök elemeit a foreach ciklus segítségével járhatjuk be. Tartsuk szem előtt, hogy a foreach csak tömbök és objektumok esetében működik, egyéb változótípus esetén hibát fog eredményezni. A szerkezete így néz ki:

foreach (tömb as $ertek) {
        esemény;
}

valamint:

foreach (tömb as $kulcs => $ertek) {
        esemény;

Az első szerkezetben a tömb elemeinek az értékét kapjuk vissza, a másodikban a tömb kulcsát is hozzárendeljük a $kulcs változóhoz. A foreach ciklus mindig a legelső elemre ugrik, és egyenként megy végig a tömb összes elemén.

--------------------

<?php
$tomb = array('első', 'második', 'harmadik');

foreach ($tomb as $ertek) {
        echo $ertek . "\n"; // Kiírja a tömb elemeit
}
?>

--------------------

Kulcsok hozzárendelése:

--------------------

<?php
$tomb = array('első', 'második', 'harmadik');

foreach ($tomb as $kulcs => $ertek) {
        echo $kulcs . ' --- ' . $ertek . "\n"; // Kiírja a tömb kulcsait és elemeit
}
?>

--------------------

 

Figyelem!
Mivel a ciklus a belső tömbmutatóra támaszkodik, annak megváltoztatása a ciklus belsejéből szokatlan viselkedést eredményezhet!

Az $ertek változóban a ciklus befejezés után benne marad az utolsó felvett érték! Ha a továbbiakban nincs rá szükségünk, akkor dobjuk el az unset($ertek); függvény meghívásával:

--------------------

<?php
$tomb = array('első', 'második', 'harmadik');

foreach ($tomb as $kulcs => $ertek) {
        echo $kulcs . ' --- ' . $ertek . "\n"; // Kiírja a tömb kulcsait és elemeit
}

echo $ertek;  // Kiírja: harmadik
unset($ertek);

echo $ertek; //  Figyelmeztetést kapunk nemlétező változóra!
?>

--------------------

 Többdimenziós (egymásba ágyazott) tömbök esetében két opciónk is van a tömb bejárására: egymásba ágyazott foreach ciklusokkal, vagy list() függvénnyel. A feladat szabja meg a választott módszert:

--------------------

<?php
$tomb = array(
'elso' => array('a','b','c'),
'masodik' => array('d','e','f'),
'harmadik' => array('g','h','i')
);

// Első módszer, egymásba ágyazott foreach szerkezetekkel:

foreach ($tomb as $kulcs => $ertek) {
        foreach ($ertek as $belso_ertek) {
                echo $kulcs . ' --> ' . $belso_ertek . "\n"; // Kiírja a tömb kulcsait és elemeit
        }
}

// Második módszer, list() függvénnyel:

foreach ($tomb as $kulcs => list($elso_elem, $masodik_elem, $harmadik_elem)) { // Tömb kibontása list() függvénnyel
        echo "$kulcs --> $elso_elem, $masodik_elem, $harmadik_elem \n";
}

?>

--------------------

-----------------------------------------------------------------------------------------------------

 

Feladatok

1. Hozzunk létre egy 5 elemes tömböt, és írassuk ki az elemek értékeit!

2. Hozzunk létre egy 3 elemes asszociatív tömböt, és írassuk ki a elemek kulcsait és értékeit! 

3. Hozzunk létre egy többdimenziós tömböt, és írjuk ki az összes elem értékét!

 

10. lecke - Vezérlő szerkezetek - for ciklus

Az előző leckékben tanult ciklusokhoz képest a for ciklus komplexebb szerkezettel és funkcionalitással bír. A működése megegyezik a C nyelv for ciklusával. A szerkezete így néz ki:

for (első_kifejezés; második_kifejezés; harmadik_kifejezés) {
esemény;
}

Az első kifejezést egyszer hajtja végre, a ciklus kezdetén, majd ellenőrzi a második kifejezés kimenetét: ha IGAZ, akkor folyatja, ha HAMIS, a ciklus véget ér. Minden ciklus végén a harmadik kifejezés kiértékelésre kerül. Bármelyik kifejezés üres is lehet, vagy több kifejezést is tartalmazhat, vesszővel elválasztva, viszont a második kifejezés esetében értéket csak az utolsó elem adja (ez dönti el, hogy véget ér a ciklus, vagy nem). A második kifejezést üresen hagyva végtelen ciklust kapunk, mivel a PHP - akár a C - alapértelmezetten IGAZ értéket feltételez - ilyenkor a ciklust a már ismert break; utasítással szakíthatjuk meg.

A legegyszerűbb példán keresztül szemléltetjük a működését:

--------------------

<?php
for ($i = 0; $i < 10; $i++) {
//Kezdőérték: 0; amíg $i kisebb, mint 10, növeljük eggyel
        echo
$i . ' '; // Kiírja az aktuális $i értékét
}
?>

--------------------

Több kifejezéses konstrukcióra példa:

--------------------

<?php
for ( $j = 10, $i = 1 ; $i < 10; $j++, $i++) {
//Kezdőértékek felvétele: $j és $i; amíg $i kisebb, mint 10, növeljük eggyel a $j-t és az $i-t is
        echo
'$i: '. $i . ' $j: ' . $j . ' '; // Kiírja az aktuális $i és $j értékét
}
?>

--------------------

 Mi történik, ha elhagyjuk az első kifejezést? Mivel a PHP nem követel előzetes változó deklarálást, így "röptében" fog létrejönni az $i változó, így lényegében a fenti teljes szerkezettel egyenértékű eredményt kapunk:

--------------------

<?php
for ( ; $i < 10; $i++) {
//Kezdőérték: NULL; amíg $i kisebb, mint 10, növeljük eggyel
        echo
$i . ' '; // Kiírja az aktuális $i értékét
}
?>

--------------------

 

Figyelem! Ha a második kifejezés is kimarad, a ciklusunk sose ér véget! Ebben az esetben szükségünk lesz a break; utasításra:

--------------------

<?php
for ( ; ; $i++) {
//Kezdőérték: NULL; nincs feltétel, viszont növeljük eggyel az $i-t
        echo
$i . ' '; // Kiírja az aktuális $i értékét
        if ($i > 9) {
// Ha az $i nagyobb, mint 9
                break;
// kitörés!
        }
}
?>

--------------------

Menjünk még tovább: hagyjuk el a harmadik kifejezést is! Észrevehetjük, hogy az $i értékét így már semmi se növeli, újabb végtelen ciklus veszély áll fenn. Ilyenkor a ciklus belsejében növelhetjük az értéket:

--------------------

<?php
for ( ; ; ) {
//Kezdőérték: NULL; nincs feltétel, nincs művelet
        echo $i . ' ';
// Kiírja az aktuális $i értékét
        if ($i > 9) {
// Ha az $i nagyobb, mint 9
                break;
// kitörés!
        }
$i++;
// Növeljük eggyel az $i-t
}
?>

--------------------

Az elhagyásos módszerek ugyanazt az eredményt produkálják, azonban figyeljünk oda egy fontos dologra: mivel a változót nem deklaráltuk, hanem futás közben jön létre, fontos biztonsági kockázatot jelent. A megoldás egyszerű: a ciklus kezdése előtt kapjon egy ellenőrzött kiindulóértéket: 

--------------------

<?php
$i = 0;
// Kezdőérték!
for ( ; ; ) {
       echo
$i;
       if ($i > 9) {
              break;
       }
$i++;
}
?>

--------------------

Megjegyzés
A for ciklusokat ugyanúgy egymásba ágyazhatjuk, mint az előző leckében tanult while ciklusokat!

 

A későbbiekben, amikor interaktív kapcsolatba lépünk a PHP programunkkal látni fogjuk, hogy milyen veszélyeket rejt magában a nem deklarált változó. Webes környezetben használt PHP alapú oldalak támadásának egyik klasszikus módjáról van szó - de ez jövőbeli tananyagok témája lesz.

-----------------------------------------------------------------------------------------------------

Feladatok

1. Írjunk egy for ciklust, ahol csak a páros természetes számokat soroljuk fel 0-tól 100-ig.

2. Írjuk le for ciklussal az angol ábécé kisbetűit; használjuk ki a string növelés módszerét!

3. For ciklust használva írjuk ki a természetes számokat tízes sorokba! Használjuk ki a vesszővel elválasztott kifejezéseket!

9. lecke - Vezérlő szerkezetek - while, do .. while ciklusok

A ciklusok, amint a nevük is mutatja, valamilyen kritérium alapú ismétlődő folyamatokat jelentenek. Szintén a valós életből vett példából kiindulva szemléltetjük a működésüket. Képzeljük el, hogy épp levest ebédelünk. Mi történik az agyunkban? A kezünk azt az utasítást kapja, hogy amíg van leves a tányérban, kanalazzunk. Ez is egy ciklus: a mozdulat ugyanaz, és addig ismétlődik, amíg az adott feltétel fennáll.

A PHP-ban a legegyszerűbb ciklus a while, a szerkezete: 

while (feltétel) {
        következmény;
}

Egy fontos dologra oda kell figyelni: a ciklus addig ismétlődik, amíg a feltétel IGAZ. A tesztelés az elején történik, vagyis ha a feltétel HAMIS értékkel indul, a ciklus belsejében levő kód sose fut le.

 Bármennyire egyszerű a ciklus szerkezete, hatalmas csapdalehetőség is egyben. Képzeljük el, mi történik, ha a feltétel értéke sose változik, és mindig IGAZ lesz. A ciklus sose ér véget, mivel az alapfeltétel az, hogy addig kell ismételni, amíg a feltétel HAMIS nem lesz. Ezt hívjuk végtelen ciklusnak. Mivel folyton ismétlődik, számtalan bajt okozhat abban az esetben, ha semmiféle megszakítás nincs a ciklusban: processzor túlterheléstől kezdve memória elfogyásán keresztül a háttértár kimerítéséig.  Ezért minden esetben járjunk el körültekintően a ciklusok létrehozásakor!

--------------------

<?php
$szam = 0;
while ($szam <= 10) {        
// Amíg a $szam kisebb vagy egyenlő 10-zel,
        echo
$szam++  . ' '; // eggyel növeli a $szam értékét, hozzáfűz egy szóközt és kiírja azt.
}
?>

--------------------

A fenti példa kiírja a természetes számokat 0-tól 10-ig. Amint látjuk, a feltétel addig IGAZ marad, amíg a $szam változó értéke el nem éri a 11-et, ami már nagyobb, mint a feltételben szereplő 10. Ekkor feltétel kiértékelése HAMIS lesz, és a ciklus véget ér.

Előfordulnak olyan esetek, amikor a feltétel kiértékelésétől függetlenül legalább egyszer le kell futnia a ciklusnak. Mivel nem tudjuk garantálni, hogy a feltétel IGAZ, vagy HAMIS értékkel indul, így a fenti while szerkezetet nem használhatjuk. Ebben az esetben a do .. while a megoldás. A do .. while ciklus a végén teszteli a feltételt, és amennyiben a kiértékelése IGAZ, újra lefut. Ez garantálja a minimum egyszeri futást. A szerkezete így néz ki:

do {
        következmény;
} while (feltétel);

Az alábbi példa szemlélteti a működést:

--------------------

<?php
$szam = 0; 
do {
        echo
$szam;     // Kiírja: 0
} while ( $szam > 0 );  
// A feltétel azonnal HAMIS!
?>

 

--------------------

Kitörés a ciklusból

Előfordulhat olyan eset, hogy nem várhatjuk meg a feltétel kiértékelését, hanem a cikluson belüli változás azonnali kilépést követel. Ilyenkor a break; kulcsszóval tudjuk azonnal befejezni a ciklust:

--------------------

<?php
$szam = 0;
while ( $szam <= 10 ) {
        echo $szam++ . ' ';
        if ($szam === 5) {
                break;    

        }
}
?>

--------------------

Ciklus a ciklusban

Az alábbi példa az egymásba ágyazott ciklusok működését mutatja be:

--------------------


$szam = 1;
$masik_szam = 1;
$betu = 'a';



        while ($masik_szam <= 10) { // Belső ciklus fut
                $masik_szam++;
                echo $betu++; // Stringet növelünk!
        }
       $masik_szam = 1; // Visszaállunk alapértékre...
       $betu = 'a';
       echo "\n";       // Új sor karakter

}
?>

--------------------

A példakód az angol ábécé első 10 betűjét írja ki 10 sorszámozott sorban: 

1:abcdefghij
2:abcdefghij
3:abcdefghij
4:abcdefghij
5:abcdefghij
6:abcdefghij
7:abcdefghij
8:abcdefghij
9:abcdefghij
10:abcdefghij

Megjegyzés
Az egymásba ágyazott ciklusok száma nincs korlátozva. Tervezésnél azonban tartsuk szem előtt a ciklusok mennyiségét: az egymásba ágyazott ciklusoknál az egyes mélységek számának szorzata lesz a véglegesen lefutott körök száma. Jelen példában: 10 x 10 = 100 ismétlődés történt: még egy szint közbeiktatásakor viszont már 1000 lenne! 

-----------------------------------------------------------------------------------------------------

Feladatok

1. Írjuk le a természetes számokat 100 és 80 között, csökkenő sorrendben!

2. Írjuk le a nevünket százszor!

3. Írjuk le az angol ábécét az "f" betűig! A feladat megoldásához használjuk a break; utasítást!

8. lecke - Vezérlő szerkezetek - if, else, elseif (else if), endif

A programok egyszerűsítve úgy működnek, hogy a kapott, előállított vagy öröklött adatokat bizonyos feltételek alapján kiértékelnek, majd a kiértékelés eredménye függvényében valamit csinálnak ezekkel az adatokkal. Valójában a mindennapi életünk során folyamatosan apró programokat futtatunk a fejünkben - akkor is, ha nem veszünk róla tudomást. Például: "ha reggel van, felkelünk az ágyból". Egyszerű, magától értetődő eseményláncolat, mégis valójában ez egy program, amit végrehajtottunk. Hogy nézne ki ez PHP-ban?

--------------------

<?php
$felkeltem_az_agybol = false; // Még mindig az ágyban fekszem
$napszak = "reggel"; // A napszakot reggelre állítjuk

if ($napszak === "reggel") { // Ha a napszak értéke "reggel", akkor...
$felkeltem_az_agybol = true; // Felkeltem az ágyból!
}
var_dump(
$felkeltem_az_agybol); // Kiírja: bool(true)


?>

--------------------

A fenti példában láthatjuk a HA (if) elem szerkezetét és működését: az if szócska után a feltétel következik zárójelbe téve, majd kapcsos zárójelben ({ ... } ) az esemény, amely akkor következik be, ha a feltétel kiértékelése igaz. Egyszerűsítve így néz ki:

if (feltétel) {
következmény;
}

Nézzünk egy másik példát! "Ha éhes vagyok, eszem, ha szomjas, iszom, ha egyik sem, akkor sétálok!". Milyen változóink lesznek? Először kell egy állapot jelző, majd egy cselekvést leíró:

--------------------

<?php
$allapot = "éhes"; // Változtassuk "éhes", "szomjas", "bármi más" értékekre a tesztelés során!
$cselekves = NULL; // Még nem csinálunk semmit, csak előkészülünk!

if ($allapot === "éhes") {            // Ha igaz, hogy éhes vagyok...
        $cselekves = "eszem";         // eszem!
}  elseif ($allapot === "szomjas") {  // Ha igaz, hogy szomjas vagyok...
        $cselekves = "iszom";         // iszom!
} else {                              // bármi más esetben...
        $cselekves = "sétálok";       // sétálok!
}

echo "Ha $allapot vagyok, $cselekves!"; /* Felhasználva az előzőekben tanultakat, mondatot alkotunk a változók értékei segítségével!
Figyeljük meg az idézőjeleket is! */


?>

--------------------

Megjegyzés
A fenti szerkezetnek létezik egy másfajta felirata is, ahol az esemény kettőspont és endif; kifejezés közé esik, ami így néz ki:

if (feltétel):
        esemény;
elseif (másik feltétel):
        másik esemény;
else:
        egyéb esemény;
endif;

Mindkét változatot szabadon használhatjuk, tetszés szerint, a további tananyagokban viszont az első, kapcsos zárójeles változatot fogjuk preferálni egyrészt a C nyelvvel való azonosság miatt, másrészt, mert a zárójelpárok vizuálisan jobban körülhatárolják az egyes részeket. Az elseif utasítás C stílusban külön írva is helyes: 

if (feltétel) {
        esemény;
} else if (másik feltétel) {
        másik esemény;
} else {
        egyéb esemény;
}

Mivel a PHP nyelv a formázással szemben nem támaszt különös igényeket (szemben a Python nyelvvel például, ahol a behúzási szintek kötik össze az összetartozó részeket), a kapcsos zárójelek helye valamint a sorok behúzása egyéni ízlés kérdése. Akár egy sorba írva is használhatjuk, ha úgy akarjuk:

if (feltétel) { esemény; } elseif (másik feltétel) { másik esemény; } else { egyéb esemény; }

Programozás közben néha előfordulhatnak olyan röviden leírható szerkezetek, ahol olvashatóbb egy sorba írva, mint tagolva. Ez is egyéni stílus - esetleg csapatban dolgozva formázási előírás - kérdése csupán.

Tanácsok
Mivel elérkeztünk ahhoz a ponthoz, hogy immár működő és hasznos programocskát is el tudunk készíteni, tartsunk szem előtt pár fontos szabályt:

  1. Mindig tervezzük meg előre a programot, és építsük fel a logikai szerkezetet! Mondjuk el magyarul, hogy mit kell tennie a programnak. Ha feltétel - következtetés szóban működőképes, akkor nagy valószínűséggel program formájában is működni fog.
  2. Csak annyi változót használjunk, amennyi feltétlenül szükséges, és mindig hozzuk őket létre úgy, hogy kiindulóértékkel látjuk el. Sok bosszúságtól kíméljük meg magunkat!
  3. Legyünk következetesek a kód formázása során! Úgy írjuk meg, hogy bármelyik másik programozó is át tudja látni és fel tudja fogni a logikáját.
  4. Törekedjünk a kód tömörségére és átláthatóságára! Ne bonyolódjunk fölösleges kódrészletek megírásába, amelyek nem vezetnek sehová!
  5. Gondoljunk a bővíthetőségre! Úgy tervezzük meg a programunkat, hogy bármikor folytatni, bővíteni lehessen!

-----------------------------------------------------------------------------------------------------

Feladatok

1. Tamás 2 éves. Ha tudjuk, hogy 18 évesen lesz a törvény szerint nagykorú, addig viszont kiskorú, vizsgáljuk meg és írjuk ki, hogy most minek tekinti a törvény!

2. Írjunk egy programot, amely megvizsgálja, hogy egy nullánál nagyobb egész szám páros, vagy páratlan! (Emlékezzünk a maradékos osztás operátorra, valamint arra a szabályra, hogy egy szám páros, ha osztható kettővel!)

3. Írjunk egy programot, amely esernyőt ajánl, ha esik az eső, napernyőt, ha süt a nap, valamint kalapot más esetekre!

7. lecke - String és tömb operátorok

Programozás során a string típusú változók tartalmát időnként össze kell fűznünk. Ezt a műveletet a string operátorokkal tudjuk elvégezni.

Két darab string operátorunk van: az első a ".", ennek segítségével két szöveg (string) típusú változót tudunk összefűzni, a második a ".=", ezzel egy létező változóhoz újabb stringet fűzhetünk hozzá:

------------------

<?php
$elso = "Szia";
$masodik = $elso . " Béla! ";


echo $masodik; // Kiírja: Szia Béla!

$masodik .= "Hogy vagy?";

echo $masodik; // Kiírja: Szia Béla! Hogy vagy?
?>

------------------

A tömbök esetében a következő műveleteket végezhetjük el: egyesítést ("+"), egyenlőség vizsgálatot ("=="), azonosság vizsgálatot ("==="), különbözőség vizsgálatot ("!=" vagy "<>") - valójában az egyenlőség tagadásáról van szó, és nem azonosság vizsgálatot ("!==") - vagyis az azonosság tagadásának vizsgálatát. 

Figyelem!
Az egyesítési operátor működése egyszerűnek tűnik, azonban kissé árnyalt a helyzet. Nézzük az alábbi példát:

------------------

<?php
$elso_tomb = array('első', 'második');
$masodik_tomb = array('harmadik', 'negyedik', 'ötödik');
print_r($elso_tomb + $masodik_tomb);
?>

------------------

Habár azt várnánk, hogy az eredmény ez legyen: Array ( [0] => első [1] => második [2] => harmadik [3] => negyedik [4] => ötödik ), mégis ezt kapjuk: Array ( [0] => első [1] => második [2] => ötödik ). A magyarázat az, hogy a jobb oldali tömböt a bal oldalira illeszti a PHP olyan módon, hogy ha kulcs azonosság van, akkor az értéket a bal oldaliból veszi így:

 -------------------------------------------------
| Első tömb    | első      |  második   |         |
| Második tömbharmadik  |  negyedik  | ötödik  |

|              |----------------------------------|
| Eredmény     | első      |  második   | ötödik  |
 -------------------------------------------------

Megjegyzés
Az első látásra várt eredményt tömb függvényekkel tudjuk elérni, ez azonban későbbi leckék anyaga lesz.

Az összehasonlító operátorok ugyanúgy működnek, mint az egyszerű változók esetén láttuk: az egyenlőség esetén nincs típusvizsgálat, csak az azonosság ellenőrzésekor.

-----------------------------------------------------------------------------------------------------

Feladatok

1. Írjuk le a teljes nevünket string operátorok segítségével úgy, hogy külön változót használjunk a családnévre, a keresztnévre és a teljes névre!

2. Hozzunk létre két eltérő elemszámú tömböt, és egyesítsük, írjuk ki az eredményt, majd vizsgáljuk meg, hogy egyenlőek-e. Használjuk a var_dump függvényt!

süti beállítások módosítása