10.1. fejezet¶
A fejezet anyaga¶
Objektumorientált programozás¶
A PHP nyelvi szinten támogatja az objektumorientált paradigma lehetőségeit. Ennek köszönhetően a Programozás-I kurzuson megismert objektumorientált koncepciók PHP-ban is megvalósíthatók. Ebben az anyagrészben megnézzük, hogy hogyan.
Osztályok, objektumok¶
Osztályok létrehozása¶
Az osztály absztrakt fogalom, konkrét életbeli objektumok, objektumcsoportok formai leírása. Az osztályok segítségével olyan objektumokat formalizálhatunk, amelyek azonos tulajdonságokkal és viselkedéssel rendelkeznek.
PHP-ban egy osztályt a következő szintaxissal hozhatunk létre:
1 2 3 4 5 |
|
Adattagok, metódusok¶
Az osztályaink adattagokat (tagváltozókat) és metódusokat (tagfüggvényeket) tartalmazhatnak. Ezeknek az elérhetőségét különböző láthatósági módosítószavakkal (access modifiers) szabályozhatjuk:
private
: az adattag vagy a metódus csak az adott osztályból elérhetőprotected
: az adattag vagy a metódus csak az adott osztályból és annak gyermekosztályaiból (lásd: öröklődés) elérhetőpublic
: az adattag vagy a metódus mindenhonnan elérhető.
PHP-ban alapból minden adattag és metódus public
láthatóságú. Ez azt jelenti, hogy ha nem adjuk meg expliciten egy adattag vagy egy metódus láthatóságát, akkor az mindenhonnan elérhető lesz.
Mivel az adattagok lényegében az osztályhoz tartozó változók, ezért a nevük elé dollárjelet ($
) írunk. A metódusok az osztály viselkedését leíró függvények, ezért őket a függvényeknél tanult function
kulcsszóval hozzuk létre.
PHP-ban az osztályok adatagjait és metódusait a ->
(nyíl) operátorral érhetjük el.
Példa: Az Ember
osztály elkezdése
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Konstruktor¶
Az osztályunk egyik speciális metódusa a konstruktor. Ez akkor fut le, amikor az osztályból egy konkrét objektumpéldányt készítünk, vagy másképp mondva az osztályt példányosítjuk.
PHP-ban az osztály konstruktora a __construct()
nevet viseli. Jellemzően a konstruktorban szoktuk elvégezni az osztály adattagjainak inicializálását (tehát az adattagok kezdőértékkel való ellátását).
A $this
beépített kulcsszó segítségével hivatkozhatunk magára az aktuális objektumra (ez nagyjából a Javából ismerős this
-nek felel meg). Fontos, hogy (Javával ellentétben) PHP-ban minden esetben ki kell írnunk a $this
kulcsszót, amikor az aktuális objektum egy adattagjára vagy metódusára szeretnénk hivatkozni!
Példa: Az Ember
osztály konstruktorának megírása és a koszon()
metódus kiegészítése az adattagok értékének kiíratásával
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Figyelem
Továbbra se felejtsük el, hogy PHP-ban nem definiálhatunk a kódban több azonos nevű függvényt (még eltérő paraméterezés esetén sem)! Ha szeretnénk, hogy a konstruktort (vagy egy egyéb metódust) eltérő paraméterszámmal is meg lehessen hívni, akkor használjuk a default függvényparamétereket!
Például az alábbi konstruktort 1, 2 és 3 darab paraméterrel is meghívhatjuk.
1 2 3 4 5 6 |
|
Destruktor, getter, setter¶
A konstruktor mellett egy másik speciális metódus a destruktor, ami az objektumpéldány megszűnésekor fog lefutni. Desktruktort a __destruct()
segítségével írhatunk PHP-ban.
Természetesen PHP-ban is van lehetőségünk getter és setter metódusokat készíteni. Ezeket jellemzően az osztály nem publikus adattagjaihoz írjuk. Emlékeztetőül: a getter az adattagok értékének lekérdezésére, míg a setter az adattagok értékének beállítására szolgál.
Példa: Létrehozunk egy destruktort az Ember
osztályon belül, valamint az $eletkor
adattaghoz írunk egy gettert és egy settert
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Objektumok létrehozása¶
A példányosítás során egy meglévő osztályból objektumpéldányt készítünk. Tehát az általános formai leírásunknak (ami az osztályunk) egy konkrét példányát készítjük el.
PHP-ban a példányosítás a new
kulcsszóval történik. Ekkor meghívjuk a példányosítani kívánt osztály konstruktorát, amelynek rendre átadjuk a szükséges paramétereket.
1 2 3 4 |
|
Példa: Az Ember
osztály példányosítása
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
|
A kód kimenete
--- Jónás létrehozva. --- --- Noémi néni létrehozva. --- 21 Szia! Jónás vagyok, egy 21 éves kőtolvaj. Szia! Noémi néni vagyok, egy 60 éves virágboltos. --- Viszlát, Noémi néni! --- --- Viszlát, Jónás! ---
Objektumok összehasonlítása¶
Objektumok összehasonlítására használhatjuk a korábban tanult ==
(dupla egyenlő) és ===
(tripla egyenlő) operátorokat.
- A
==
operátor pontosan akkor ad vissza igazat, ha a két objektum adattagjainak a neve és értéke rendre megegyezik. - A
===
operátor pontosan akkor ad vissza igazat, ha a két objektum ugyanaz az objektum.
Példa: Objektumok összehasonlítása
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Objektumok másolása¶
Tekintsük az előző kódpéldában az $ember3 = $ember1
értékadást! PHP-ban az objektumok alapértelmezetten referencia szerint működnek, ezért itt az $ember3
egy referencia lesz, ami ugyanarra az objektumra mutat, mint az $ember1
. Ekkor tehát nem jön létre egy új objektum.
A referencia szerinti működésnek az egyik következménye, hogy ha a példában az $ember1
vagy $ember3
objektumok közül az egyiket valahogyan módosítjuk (pl. megváltoztatjuk az ember életkorát), akkor a másik objektum is ugyanígy fog változni.
Példa: Az objektumok referencia szerint működnek
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
A kód kimenete
Szia! Károly vagyok, egy 40 éves gyártulajdonos. Szia! Károly vagyok, egy 40 éves gyártulajdonos.
Ha azt szeretnénk, hogy egy teljesen új objektumot hozzunk létre, amit az eredeti objektumtól függetlenül módosíthatunk, akkor használjuk a clone
kulcsszót!
Példa: Objektum klónozása
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Kimenet
Szia! Károly vagyok, egy 20 éves gyártulajdonos. Szia! Károly vagyok, egy 40 éves gyártulajdonos.
Az osztályunkban definiálhatunk egy __clone()
nevű metódust is, amely a clone
kulcsszó hatására automatikusan meghívásra kerül. Ebben lehetőségünk van a létrejövő másolat objektum adattagjainak módosítására is.
Példa: A klónozás során 10 évvel növeljük az életkort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
A kód kimenete
Szia! Károly vagyok, egy 20 éves gyártulajdonos. Szia! Károly vagyok, egy 30 éves gyártulajdonos.
A const
és static
kulcsszavak¶
A const
kulcsszóval konstans adattagokat hozhatunk létre egy osztályon belül. A konstans adattagok neve elé nem írunk dollárjelet, és természetesen a kezdőértékük sem változhat meg (megjegyzendő viszont, hogy öröklődéssel a konstansok felüldefiniálhatók).
A konstans adattagok elérése az osztályon belül a self::ADATTAG_NEVE
szintaxissal, az osztályon kívül pedig az OsztalyNeve::ADATTAG_NEVE
segítségével lehetséges.
Példa: Konstans adattag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
A kód kimenete
3.14 62.8
A static
kulcsszóval statikus adattagokat is készíthetünk egy osztályban. Az ilyen adattag egyetlen példányban léteznek a memóriában, és az osztály minden példánya osztozik rajta. Tehát tulajdonképpen a statikus adattagok valójában nem is az objektumhoz, hanem magához az osztályhoz tartoznak.
A statikus adattagokra az osztályon belül a self::$adattagNeve
szintaxissal, az osztályon kívül pedig az OsztalyNeve::$adattagNeve
(vagy $objektum::$adattagNeve
) segítségével hivatkozhatunk szabályosan.
Példa: Statikus adattag, amivel számon tartjuk, hogy hány Ember
objektumot hoztunk létre
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Kimenet
3 emberünk van. 3 emberünk van.
Megjegyzés
Természetesen nem csak az adattagok, hanem egy osztály metódusai is lehetnek statikusak. A statikus metódusokon belül a $this
objektum nem érhető el!
Öröklődés¶
A Programozás-I kurzusról ismerős lehet számunkra az öröklődés fogalma. Ez egy osztályok közötti kapcsolat, amely egy úgynevezett ősosztály (szülőosztály) és egy gyermekosztály (leszármazott osztály) között valósul meg. A gyermekosztály tulajdonképpen az ősosztályának egy speciális változata lesz (pl. a Kutya
osztály az Allat
osztály gyermeke, hiszen minden kutya egyben állat is).
Az öröklődés során a gyermekosztály megörökli az ősosztályának az összes adattagját és metódusát. A gyermekosztályban létrehozhatunk az örökölteken kívül további adattagokat és metódusokat is, valamint lehetőségünk van az örökölt metódusok működésének felüldefiniálására is (overriding).
PHP-ban az öröklődést a következő szintaxissal valósíthatjuk meg:
1 2 3 4 5 |
|
Fontos megjegyezni, hogy PHP-ban csak egyszeres öröklődés van, azaz egy osztálynak nem lehet kettő vagy több ősosztálya. Ez természetesen nem zárja ki azt, hogy egy osztálynak több gyermekosztálya legyen, vagy hogy a gyermekosztálynak lehessenek saját gyermekosztályai.
A parent
kulcsszóval hivatkozhatunk a gyermekosztályból az ősosztályra, annak adattagjaira és metódusaira: parent::$adattagNeve
, parent::metodusNeve()
.
Példa Öröklődés - A Hallgato
osztály az Ember
osztály gyermeke, hiszen minden hallgató egyben ember is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
|
A kód kimenete
Szia! Margit vagyok, egy 72 éves nyugdíjas. Ricsi (NEP4LF) vagyok, egyetemi hallgató. Tomi (ASD123) vagyok, egyetemi hallgató. Ricsi sajnos nem kap ösztöndíjat. Tomi ösztöndíjban részesül. Hurrá!
Típusellenőrzés¶
Ha PHP-ban egy $obj
objektumról el szeretnénk dönteni, hogy az Oszt
osztály példánya-e, akkor az $obj instanceof Oszt
konstrukciót használjuk.
Példa: Típusellenőrzés az instanceof
kulcsszóval
1 2 3 4 5 6 7 8 9 10 |
|
A final
kulcsszó¶
A final
kulcsszót két fontosabb célra használhatjuk:
- Metódusok esetén megakadályozhatjuk a metódus felüldefiniálását a gyermekosztályokban a segítségével.
- Osztályok esetén megakadályozhatjuk az osztályból való örököltetést a használatával.
Ha egy final
kulcsszóval ellátott metódust felül akarunk definiálni, vagy egy final
kulcsszóval ellátott osztályból örököltetünk, akkor végzetes hibát (Fatal Error) kapunk.
Példa: A final
kulcsszó használata
1 2 3 4 5 6 7 8 9 10 11 |
|
Az abstract
kulcsszó¶
Az abstract
kulcsszó segítségével absztrakt metódusokat, illetve absztrakt osztályokat hozhatunk létre PHP-ban.
Absztrakt metódusok¶
Az absztrakt metódusok olyan metódusok, amelyek nem rendelkeznek funkcióval az osztályon belül. Ezeket az absztrakt metódusokat a gyermekosztályban kell majd funkcióval ellátni.
Például ha van egy Allat
osztályunk, aminek van egy hangotAd()
metódusa, akkor ezt a metódust absztrakttá tehetjük, hiszen egy állatról nem tudjuk általánosságban megmondani, hogy milyen hangot ad. Viszont az Allat
osztályból örököltetett Macska
osztályról már pontosan tudjuk, hogy milyen hangot ad ("Miaú!"), ezért ebben az osztályban már implementáljuk a hangotAd()
metódust.
Absztrakt osztályok¶
Ha egy osztály tartalmaz legalább 1 absztrakt metódust, akkor az osztály is kötelezően absztrakt kell, hogy legyen! Az abstract
kulcsszóval ellátott osztályok nem példányosíthatók.
Az absztrakt osztályból származó gyermekosztályban az összes absztrakt metódust felül kell definiálni (ellenkező esetben a gyermekosztálynak is absztraktnak kell lennie)!
Példa: Absztrakt metódus és absztrakt osztály
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
A kód kimenete
Miaú! Miaú!
Interfészek¶
PHP-ban az interface
kulcsszóval létrehozhatunk interfészeket is, amelyek csak publikus absztrakt metódusokat és osztálykonstansokat tartalmazhatnak. Az interfészekben definiált absztrakt metódusok esetén az abstract
kulcsszót nem írjuk ki.
Ha azt szeretnénk, hogy egy osztály megvalósítson (más szóval implementáljon) egy adott interfészt, akkor ezt az implements
kulcsszóval tehetjük meg. Ekkor az interfészt megvalósító osztályban az interfész összes absztrakt metódusát felül kell definiálnunk, különben az osztályt absztrakttá kell tennünk.
Egy osztály egyszerre akár több interfészt is megvalósíthat (ekkor a megvalósított interfészeket vesszővel elválasztva adjuk meg az implements
kulcsszó után). Emiatt az interfészeket használhatjuk akár a többszörös öröklődés hiányának megoldására is.
Tipp
A többszörös öröklődés hiányára egy másik megoldást nyújtanak a trait-ek. Róluk ezen a linken, illetve az előadáson tanulhatunk.
Példa: Interfészek használata
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
A kód kimenete
Garfield vadászik... Garfield megette: lasagne.
Gyakorló feladat¶
Feladat
Egészítsük ki az előző fejezetekben elkezdett projektünket objektumorientáltsággal! A feladat egy felhasználói hozzászólások írására szolgáló funkció elkészítése a projekt főoldalán.
-
Hozzunk létre egy
Komment
osztályt, amely egy felhasználói hozzászólást fog reprezentálni! Egy kommentről tároljuk el a hozzászólást író felhasználó nevét (továbbiakban: szerző), a kommentelés időpontját és a komment szövegét! Ezek legyenek privát adattagok, amelyekhez készítsünk getter és setter metódusokat! Egy új komment létrehozásakor a konstruktor paraméterben kapja a szerzőt, az időpontot és a komment szövegét, és ezekkel inicializálja az adattagokat. -
Hozzunk létre egy kezdetben üres
comments.json
fájlt! Ebben a fájlban fogjuk tárolni a kommentek adatait. Írjuk meg afunctions.php
-ban aloadComments($path)
éssaveComments($path, $comments)
függvényeket! Az előbbi függvény a kommentek fájlból való betöltéséért, utóbbi pedig a hozzászólások fájlba történő elmentéséért felel. -
A főoldalon (
index.php
) listázzuk ki a meglévő kommenteket egy-egy<div>
-ben! Jelenítsük meg a kommentet író felhasználó nevét és profilképét, a komment dátumát és szövegét! Amennyiben még nem érkezett egyetlen komment sem, akkor írassuk ki a "Még nem érkezett hozzászólás." szöveget ehelyett! -
A bejelentkezett felhasználók számára jelenítsünk meg a kommentek kilistázása alatt egy új komment írására alkalmas űrlapot! Helyezzünk el ezen egy több soros beviteli mezőt, valamint egy elküldés gombot!
-
Miután egy felhasználó új kommentet írt, akkor dolgozzuk fel azt a következő szempontok szerint:
- Ha a beviteli mezőt nem töltötte ki a felhasználó, akkor írassunk ki hibaüzenetet!
-
Egy komment legfeljebb 500 karakter hosszú lehessen, ha ettől több karaktert ad meg a felhasználó a beviteli mezőben, akkor írassunk ki hibaüzenetet!
- Ha nem találtunk semmilyen hibát az űrlapfeldolgozás során, akkor a bejelentkezett felhasználó nevének, a beírt komment szövegének és az aktuális időpontnak (lásd: lentebb) a felhasználásával példányosítsunk egy új
Komment
objektumot! Mentsük el az új kommentet acomments.txt
-be (saveComments()
függvény), majd ezután töltsük újra a weboldalt!
Segítség az aktuális dátum és időpont lekéréséhez:
1 2 3 4 5 |
|
Megoldás (Komment.php)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
|
Megoldás (functions.php)
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Megoldás (kommentek feldolgozása)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Megoldás (kommentek listázása)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Megoldás (Komment írás)
1 2 3 4 5 6 7 8 9 |
|