Mire van szükségünk?
- konstans/statikus elérés
- objektumot kapjunk vissza
- annak típusa egyezzen meg az enum típusával
- adott konstanson keresztül mindig ugyanazt az objektumot kapjuk meg
PHP-ben egy konstans nem tárolhat objektumot, ezért marad a statikus elérés. Statikus blokk szintén nincs PHP-ben, ezért valamikor kézzel triggerelni kell az inicializációt, erre lehetőségünk van az osztály definíció után. Az inicializáció során reflectionnel meg kell keresni az összes publikus static fieldet, példányosítani a megfelelő névvel az enumot és letárolni a fieldben.
Példa
Nagyjából ezt valósítottam meg a precore libben lévő Enum osztályban. Nézzünk rá egy példát. Vegyük a hét napjait.
|
|
Amint az autoloader betölti a fájlt, lefut a Day::init()
statikus metódus, és innentől fogva minden statikus fieldben egy Day típusú objektum lesz. Ha segíteni akarunk az IDE-nek, írjuk mindegyik fölé a típust PHPDoc-ban. Az Enum osztály ad nekünk néhány metódust. Ilyen például a name(), ami visszaadja stringként a field nevét: Day::$MONDAY->name() == "MONDAY"
. Vannak statikus metódusok, mint például a valueOf()
, ami a string alapján visszaadja nekünk az objektumot: Day::valueOf("MONDAY") == Day::$MONDAY
és a values()
, amivel pedig megkapjuk az összes objektumot.
Nem titok, ezek a dolgok Javaból jönnek. Viszont az még tud pár dolgot. Tegyük fel, hogy egy dayOfWeek()
metódust szeretnénk írni, ami visszaadja, hogy az adott nap a hét hanyadik napja. Bővítsük ki az osztályunkat.
|
|
A switch nagyon nem szép
Tényleg nem és Javaban ezt sokkal szebben is el lehet intézni, méghozzá konstruktorral. No de a konstruktor nem lehet publikus, mert statikusan érhetjük el csak az objektumokat, vagyis maximum protected lehet. Viszont honnan hívjuk? PHP-ben ez problémás, de készítettem erre is workaroundot. Bővítsük az osztályt egy új függvénnyel és a konstruktorral, vegyük fel az új propertyt és módosítsuk a metódusunkat:
|
|
A constructorArgs()
-ban definiált paramétereket sorra meg fogja kapni a konstruktor. Bár jelen esetben nem feltétlenül kapunk rövidebb kódot, azonban
- minden switchet meg lehet így spórolni, amennyiben több metódusban is hasonló logikát szeretnénk beépíteni, ugyanis több paramétert átadhatunk a konstruktornak
- a switch minden metódus hívásnál kiértékelődik, ezzel a módszerrel pedig csak egyszer kell ezt megtenni
- tervezem, hogy mindezt annotációval is el lehessen érni, és akkor elég csak a konstansnál definiálni a konstruktor paramétereit (természetesen ez nem fed le minden esetet)
Valós példa
Készítettem egy TimeUnit enumot, amivel az időegységeket tudjuk könnyen kezelni (igen, ez is Javaból van). A szép az egészben, hogy tetszőleges függvénynek átadhatunk egy TimeUnit objektumot.
|
|
Na mit fog ez kiírni?
Az Enum-ot és még néhány hasznos osztályt a precore libraryben érhetitek el, illetve composerrel is telepíthetitek. Aki a nagyjából 100 soros implementációra kíváncsi, az itt kutakodjon.