Tömbök I.
Tömbök létrehozása
Az elkövetkezendő három leckében egy új adattípussal fogunk foglalkozni, amit tömbnek nevezünk. A tömb egy összetett adattípus, ami azt jelenti, hogy az eddig megismert adattípusokból építhető fel. Az eddig megismert adattípusokat egyszerű adattípusoknak nevezzük: logikai típus, egész szám, lebegőpontos szám és karakterlánc. Egy tömb általában azonos típusú adatokat tartalmaz, de rakhatunk bele különbözőeket is.
Példaként nézzünk egy egyszerű esetet, mondjuk egész számokból álló tömböt. Ilyet akkor hozunk létre, ha például több számot egyetlen egységként szeretnénk kezelni. Tegyük fel, hogy a 10-nél kisebb prímszámokkal szeretnénk dolgozni, vagyis ezekkel: 2, 3, 5, 7. Nyilván ezt megtehetjük például így:
$prim1 = 2; $prim2 = 3; $prim3 = 5; $prim4 = 7;
Majd ezekkel a változókkal szórakozhatunk. Azonban sokkal jobb megoldás, ha létrehozunk belőlük egy $prim nevű tömböt. Egy ilyen tömböt grafikusan valahogy így lehet elképzelni:

A tömböt tehát nem úgy érdemes elképzelni mint egy halmazt, mivel itt fontos a sorrend! A számokat a tömb elemeinek nevezzük, és az első elem a 2-es szám, a második a 3-as, ... az utolsó pedig a 7-es.
A PHP-ben tömböt az array() függvénnyel tudunk létrehozni:
$prim = array();
Persze ez így még nem túl megnyerő, mivel egyetlen elemet sem tartalmaz. Egyenként is berakosgathatjuk az elemeket, de az array() függvény paraméterlistájában is megtehetjük ezt, így létrehozáskor azonnal fel is tölthetjük a tömböt:
$prim = array(2, 3, 5, 7);
Látható, hogy az array()-t ugyanúgy használhatjuk, mint bármelyik másik függvényt, a különlegessége annyi, hogy tetszőleges számú és típusú paramétereket belerakhatunk. A paraméterek a megadott sorrendben bekerülnek a tömbbe.
Elemek elérése
Miután létrehoztuk a $prim tömbünket, nem ártana, ha be tudnánk olvasni az elemeit. Mit csináljunk, ha például ki szeretnénk íratni a benne lévő számokat? Próbálkozzunk a szokásos módszerrel:
print $prim;
Ez azt fogja kiírni, hogy Array, vagyis a változó típusát írattuk ki. Az a probléma, hogy itt több számról van szó, amiket csak egyenként tudunk kiíratni. A tömb egy elemét úgy tudjuk elérni, hogy a tömb neve után szögletes zárójelek közé írjuk az elem sorszámát, például így: $prim[2]. Vagyis az alábbi kód az egyik elemet írja ki:
print $prim[2];
Ha kipróbáljuk, akkor érdekes módon az 5-ös számot dobja elénk, vagyis a harmadik számot sikerült kiíratnunk. Fontos tudni, hogy a PHP-ben (és a legtöbb más programozási nyelvben is) a tömbök elemeinek számozása alapértelmezés szerint 0-val kezdődik, vagyis az első elem sorszáma 0, a másodiké 1, ... an n-edik sorszáma n-1. A tömb elemének sorszámát az elem indexének szokás hívni. Az "alapértelmezés szerint" azt jelenti, hogy az indexelést meg lehet változtatni, nemsokára megtudjuk, hogyan. Addig is, ha például vesszővel elválasztva ki szeretnénk íratni a tömb elemeit, megtehetjük így:
print $prim[0].", ".$prim[1].", ".$prim[2].", ".$prim[3];
Ha egy olyan elemet próbálunk kiíratni, ami nem létezik (pl. $prim[-1] vagy $prim[4]), akkor nem íródik ki semmi. Az ilyenek használatával ugyanazt a hatást érjük el, mint egy nem létező változó használatával. Így például az isset($prim[4]) vizsgálat false értéket ad vissza.
A kiíratás csak egy példa volt, a tömb elemeire való hivatkozásokat (pl. $prim[2]) ugyanúgy használhatjuk, mint bármilyen más változót. A tömb nevét (pl. $prim) viszont csak ott használhatjuk változóként, ahol annak van értelme. Láthattuk, hogy kiíratásnál nem sok értelme van, de átadhatjuk például egy függvénynek paraméterként, vagy szerepelhet értékadásban is.
Ertékadás
Tömböknek nem csak az array() függvénnyel adhatunk értéket, bár ez a leggyakoribb. Tömbnek értékül adhatunk egy, már korábban létrehozott tömböt is:
$prim = array(2, 3, 5, 7); $szamok = $prim;
Itt például a $szamok tömb jött létre, aminek egy másik tömbbel adtunk értéket. A $szamok és a $prim tömbök teljesen egyformák lesznek. Egy tömböt úgy is létrehozhatunk, illetve értékeket rakhatunk bele, hogy az egyes elemeket külön-külön adjuk meg. Például:
$prim = array(); $prim[0] = 2; $prim[1] = 3; $prim[2] = 5; $prim[3] = 7;
Vagyis létrehoztunk egy üres tömböt, majd egyenként feltöltöttük. A $prim[2] = 5; értékadás például azt csinálja, hogy ha eddig nem volt a tömbnek kettes indexű (sorszámú) eleme, akkor létrehozza, ha volt, akkor felülírja. Ez a művelet a többi elemtől teljesen függetlenül történik, ami azt jelenti, hogy lehet egy olyan tömbünk is, ami csak egy kettes indexű eleme van. Hasonló módon érhetjük el azt, hogy ne 0-val, hanem mondjuk 1-gyel kezdődjön az indexelés:
$prim = array(); $prim[1] = 2; $prim[2] = 3; $prim[3] = 5; $prim[4] = 7;
Így a tömbnek nem lesz 0-adik eleme, az indexelés 1-gyel kezdődik. Az utolsó (vagyis a legnagyobb indexű) elem után hozzáfűzni a $prim[] = 11; módon lehet. Vagyis a fenti példát így is írhatjuk:
$prim = array(); $prim[1] = 2; $prim[] = 3; $prim[] = 5; $prim[] = 7;
Ha a szögletes zárójelek közé nem írunk semmit, az ebben az esetben az utolsó utáni elemre hivatkozik. Ez a harmadik sorban a 2-es indexű, majd a 3-as, stb. Ha üres tömbre alkalmazzuk ezt az értékadást (pl. a második sorban $prim[] = 2;), akkor az 0 indexű elemként kerül a tömbbe, mivel ez az alapértelmezett sorszáma az első elemnek.
Az indexelő operátor
A fent használt [] szögletes zárójelpár valójában egy operátor, aminek két operandusa van. Az első operandus a nyitó zárójel elé kerül, a második pedig a nyitó és csukó közé: op1[op2]. Az első operandus egy tömb neve kell hogy legyen, a második viszont tetszőlegesen bonyolult kifejezés is lehet. A kifejezés értéke egy egész szám vagy egy karakterlánc lehet (utóbbi esettel a következő leckében foglalkozunk).
Mivel a második paraméter tetszőlegesen bonyolult kifejezés lehet, az alábbi példa is helyes:
$n = 5;
$gyumolcs = array("alma", "körte", "málna", "barack", "dinnye");
print $gyumolcs[date("s", time()) % $n];
Ebben a példában egy karakterláncokat tartalmazó tömböt hoztunk létre, ami ezen kívül semmiben sem különbözik az egész számokat tartalmazó tömbtől. A tömb elemeinek indexelése 0-tól 4-ig megy. A date() függvény egy 0 és 59 közötti egész számmal tér vissza, nagyjából véletlenszerűen (attól függ, hogy hány óra van, pontosabban hogy az óra hanyadik másodpercnél jár). Majd ennek a számnak vesszük az 5-tel vett osztási maradékát, így egy 0 és 4 közötti számot kapunk. A print tehát mindig valamelyik gyümölcs nevét fogja véletlenszerűen kiírni.
A [] operátor a második "legszorosabban kötő" operátor, így sosem kell zárójelbe tenni egy ilyen kifejezést: ($tomb[3]). A legszorosabban kötő operátor egyébként a függvényhívás operátora, ami a () kerek zárójelpár (igen, valójában ez is egy operátor), ahol az operandusok teljesen hasonló módon viselkednek: op1(op2). Az első operandus egy függvény neve, a második pedig egy paraméterlista.
Házi feladat
1.) Próbálj írni egy olyan ciklust, ami a $gyumolcs tömb elemeit sorban egymás után kiírja, mondjuk vesszővel elválasztva! Tegyük fel, hogy nem tudod, hány eleme van a tömbnek.
(Segítség: használd az isset() függvényt!)
Ilyen példa nem volt a leckében, de úgy gondoltam, nem lesz nehéz rájönni, hogy az isset($gyumolcs[$n]) kifejezés true értéket ad vissza, ha az $n-edik elem létezik, false értéket, ha nem. Ez le is volt írva, csak nem a $gyumolcs tömbre. Vagyis a megoldás:
for ($n = 0; isset($gyumolcs[$n]); ++$n){
print $gyumolcs[$n].", ";
}
Ahhoz, hogy ez jól működjön, csak azt kell tudni, hogy melyik számmal kezdődik a tömbelemek indexelése, mivel $n kezdőértékét erre kell beállítani.
2.) Rakd be egy tömbbe 1-től 100-ig az összes egész számot, majd írj hozzá egy olyan programot, ami véletlenszerűen kiírja az egyiket (használhatod az imént látott módszert, amiben az aktuális idő határozta meg a kiírandó számot)! Gondoskodj róla, hogy mindegyik számnak legyen esélye arra, hogy a böngésző ablakában szerepeljen!
A 100 darab szám tömbbe rakását érdemes ciklussal elvégezni:
$szam = array();
for ($n = 1; $n <= 100; ++$n){
$szam[] = $n;
}
Amikor még üres a tömb, a $szam[] = $n; kifejezés 0-adik elemként rakja a tömbbe az első számot, majd minden lépésnél a tömb végéhez fűzi a következőt.
A feladat második részén már kicsit többet kell gondolkodni. Nyilván az a probléma, hogy most nem elegendő a másodpercek száma, ami a date("s", time()) visszatérési értéke, mivel az csak 60-féle számot ad, de nekünk 100-féle közül kell választanunk. A problémát sokféleképpen meg lehet oldani. Például kombinálhatjuk a másodpercek számát a percek számával (mondjuk a kettő összegének a 100-zal vett osztási maradékát vesszük), de az egyik legegyszerűbb megoldás már az orrunk előtt van, nem kell hozzá semmiféle bűvészkedés! Egyszerűen használjuk a date() függvény második paraméterét! A time() függvény az 1970 óta eltelt másodpercek számát adja vissza, ami bőven 100 fölött van, ráadásul ez is minden másodpercben más értéket ad. Így egy lehetséges megoldása a feladatnak, ha a tömb feltöltése után az alábbit írjuk:
print $szam[time() % 100];
A $szam tömb indexelése 0 és 99 között fut, és a time()%100 kifejezés pontosan ilyen számokat ad, mivel egy számot 100-zal osztva a maradék csak ilyen lehet. Ebből látható, hogy a fentebb látott példa igazából túl volt bonyolítva, de azzal inkább csak a [] operátor használatát szerettem volna szemléltetni.







