Autoloading & namespaces: class not found [megoldott]
Névtér alapú autoloadingot próbálgatom tanulási céllal, amit pseudo-static osztályhívással kombinálnék (Osztaly::nemLetezoDinamikusMetodus()), á lá laravel, ám "class not found" hibát kapok. Mi lehet az oka?
Az elképzelés az, hogy egyedi autoloader regisztrálásával a névterek alapján csinálok autoloadingot, valamint a facade és inverse of control minták alapján osztály alias-ok szerint egy object containerből feloldom az objektumok nevét, hogy a kódban ilyen hívásokat tudjak csinálni:Ugyanakkor pl. tesztelhetőség miatt ezt nem statikusan szeretném megoldani, hanem a kívánt osztályok betöltésével.
A könyvtárszerkezet:Az állományok tartalma:
- index.php: http://pastebin.com/Jz128edU
- Facade.php: http://pastebin.com/VUCRuNRk
- Iharos.php: http://pastebin.com/SYyR6PeY
- Label.php: http://pastebin.com/1mhEMmeJ
- LabelModule.php: http://pastebin.com/ereT9v7s
Az Iharos.php-ban lévő Iharos->autoLoader() valósítja meg a névtér alapú autoloadingot.
Konkrétan az index.php futásakor azt szeretném, hogy a Facade osztályt kiterjesztő Label osztály automatikus betöltése után a Facade::__callStatic() fusson le, ami az Iharos->manifest() alapján feloldja és szükség esetén példányosítja a kívánt modult (LabelModule), majd meghívja annak nem statikus label() metódusát. Azért használok külön Label és LabelModule osztályokat, hogy ne legyen "static call on non-static method" hiba.
A pseudo-static hívásokig nem jutok el, a kimenet ez:
Mindenféle kombinációit kipróbáltam a névtereknek, elolvastam egy vagon autoloading és névtér cikket, kézikönyvet, laravel forráskódját is böngésztem, stack overflow is a barátom, de nem jövök rá a megoldásra.
1. Mi okozza a fenti hibát? (Névterek?)
2. Van bevett gyakorlat ilyen jellegű hibák felderítésében, tesztelésében?
3. Lehet a pseudo-static hívásokat egyszerűbben is modellezni?
Hálás lennék a segítségért, napok óta küzdök evvel. :)
■ Az elképzelés az, hogy egyedi autoloader regisztrálásával a névterek alapján csinálok autoloadingot, valamint a facade és inverse of control minták alapján osztály alias-ok szerint egy object containerből feloldom az objektumok nevét, hogy a kódban ilyen hívásokat tudjak csinálni:
Label::label("cimke")
A könyvtárszerkezet:
/
index.php
Iharos/
Kernel/
Facade.php
Iharos.php
Label
Label.php
LabelModule.php
- index.php: http://pastebin.com/Jz128edU
- Facade.php: http://pastebin.com/VUCRuNRk
- Iharos.php: http://pastebin.com/SYyR6PeY
- Label.php: http://pastebin.com/1mhEMmeJ
- LabelModule.php: http://pastebin.com/ereT9v7s
Az Iharos.php-ban lévő Iharos->autoLoader() valósítja meg a névtér alapú autoloadingot.
Konkrétan az index.php futásakor azt szeretném, hogy a Facade osztályt kiterjesztő Label osztály automatikus betöltése után a Facade::__callStatic() fusson le, ami az Iharos->manifest() alapján feloldja és szükség esetén példányosítja a kívánt modult (LabelModule), majd meghívja annak nem statikus label() metódusát. Azért használok külön Label és LabelModule osztályokat, hogy ne legyen "static call on non-static method" hiba.
A pseudo-static hívásokig nem jutok el, a kimenet ez:
app->registerAutoLoader()
app->autoLoader(Label)
autoLoader: /var/www/teszt/Iharos/Label/Label.php
app->autoLoader(Iharos\Kernel\Facade)
autoLoader: /var/www/teszt/Iharos/Kernel/Facade.php
Fatal error: Class 'Iharos\Kernel\Facade' not found in /var/www/teszt/Iharos/Label/Label.php on line 8
app->autoLoader(Label)
autoLoader: /var/www/teszt/Iharos/Label/Label.php
app->autoLoader(Iharos\Kernel\Facade)
autoLoader: /var/www/teszt/Iharos/Kernel/Facade.php
Fatal error: Class 'Iharos\Kernel\Facade' not found in /var/www/teszt/Iharos/Label/Label.php on line 8
Mindenféle kombinációit kipróbáltam a névtereknek, elolvastam egy vagon autoloading és névtér cikket, kézikönyvet, laravel forráskódját is böngésztem, stack overflow is a barátom, de nem jövök rá a megoldásra.
1. Mi okozza a fenti hibát? (Névterek?)
2. Van bevett gyakorlat ilyen jellegű hibák felderítésében, tesztelésében?
3. Lehet a pseudo-static hívásokat egyszerűbben is modellezni?
Hálás lennék a segítségért, napok óta küzdök evvel. :)
Egyszerű hibakeresés PHP
PHP Framework Interop Group
Autoloading Standard
Kicsit megnéztem a Iharos
Iharos
class-t.Szerintem légyszíves kezd a php dokumentációjával!
Már a
constructor
eleje problémás:return static::$instance;
De egyébként hemzseg a hibától!
- Ez helyet
'Iharos\Kernel\Iharos'
lehet ezt'Iharos\\Kernel\\Iharos'
akartad írni.(?)-
error
föggvény helyett ->throw new Exception('error message');
-
getInstance
inkább ilyen legyen
Re: Egyszerű hibakeresés PHP
A debug_backtrace() hasznos, PSR-0, PSR-4 standardokat ismerem, de a lehető legegyszerűbb példában nem látom értelmét használni őket.
Nem, mivel a backslash escape karakter.
Az error metódus célja csak annyi, hogy egy helyen kelljen csak módosítani, ahogy játszom a kóddal, plusz kivételt amúgyis macerás dobni autoloaderből, ami megint csak bonyolítaná a példát.
Mindenesetre ha bármi éles lesz ebből, abban tanácsod szerint kivételek lesznek.
Az Iharos szerintem singletonként viselkedik, emiatt a static vs self különbségnek nem szabadna megjelennie, de igazad van, a pontosság jegyében a self való ide.
Köszönöm a tanácsokat, megfogadom őket, sajnos azonban ezek egyike sem hoz megoldást. Bármi egyéb ötlet?
névterek
A névtér ne tartalmazza az adott osztály nevét.
Pl. Facade.php esetében: namespace Iharos\Kernel;
re:névterek
A névtereket rendbetettem a tanácsod szerint, de továbbra is a kezdőbejegyzésben leírt hibát kapom.
Az osztályokat tartalmazó állományokat betölti az autoloader, így itt továbbra is valami névtér probléma lesz.
Az egyszerűség kedvéért feltettem a kódot githubra:
https://github.com/iharos/iharos
Bármi ötlet?
A Label.php betoltodesekor az
Köszönöm, ez a megoldás :)
A röhej az, hogy éreztem, hogy valami triviális történik, ugyebár két sorral feljebb pontosan így példányosítottam az Iharos\Kernel\App-ot, de teljesen beakadt egy gondolatmenet... ezért jöttem a Weblaborra. :)
Az előttem lévő hozzászólást...
Neked is köszönöm :)
Köszi, hogy feltetted a
Nekem nem világos, hogy az
Iharos\Kernel\Iharos
osztály pontosan mi célt szolgál? Olyan "svájci bicska" osztálynak tűnik:$app = new Iharos\Kernel\Iharos();
Ez szerintem nem jó. Egy osztály egy dolgot csináljon, de azt jól.
Aztán van benne egy-kettő olyan apró dolog ami most jó ötletnek tűnik, de később, mikor már a projekt megnő, igen bosszantó hibákat fog eredményezni.
Pl:
A php a
__DIR__
állandóban a végén nem tárol path separátort,te viszont a
base_dir
-ben igen. Ez szerintem nem konzisztens a php-val.A "globális" (gondolom annak tervezted) osztály factory,
manifest
függvény, nagyon meg fogja nehezíteni a hibakeresést. Persze csak akkor ha működik ($module = $this->module_registry[$name];
).Én azt javaslom, hogy legyen egy autoloader osztályod. Az ne csináljon, ne tudjon semmi mást csak osztályokat betölteni. De azt tudja!
Néhány link amit érdemes ehhez átolvasnod:
A keveredő feladatokról...
Igen, jogos, keveredett az autoloader, a factory és facade feloldás. Szebb és praktikusabb a linux-szerű "egyet, de jól" megközelítés, még a bejegyzésed olvasása előtt a githubon lévő friss megoldásban csak az autoloadert és a facade feloldást tartottam meg.
Szerk.: A cél egyébként csak annyi volt, hogy megértsem a névtér alapú autoloadingot úgy, hogy mindezt kombinálom a pseudo-static hívással, vagyis tudjak úgy csinálni, mint a laravel. :))
Elegáns. :)
Pont ilyesmiket szeretnék megtanulni, tudnál erről bővebben írni? Ha arra gondolok, amire te, akkor valószínűleg a mostani verzióban szereplő App::resolve() is ugyanide vezet.
Köszönöm a linkeket!
Megoldás githubon forráskóddal
Egy átgondoltabb, kitisztított változatot feltettem githubra, ennek előnyei a korábbihoz képest (szerintem ^^):
- PSR-4 compliant autoloader
- nem szükséges a Label (vagy bármi hasonló) névterének megadása
- a Kernel\App (néhai Kernel\Iharos) nem kell, hogy singleton legyen
- a Kernel\App nem akar factory is lenni
- code cleanup