ugrás a tartalomhoz

Osztálybetöltési sorrend autoloader nélkül wildcard szabályokkal

janoszen · 2011. Feb. 10. (Cs), 22.30
Sziasztok!

Előre bocsájtom, hogy a projekt és ezzel a kérdés is meglehetősen kísérleti jellegű és önkényesen szűkre szabott peremfeltételekkel rendelkezik.

A kísérlet tárgya egy PHP-ban írt, FastCGI-t beszélni képes daemon. (Természetesen közelről sincs készen.) A probléma az osztály betöltéssel van, ugyanis azt a feltételt szabtam, hogy lehetőség szerint töltsön be minden osztályt, fájlt, stb. előre, tehát az autoloading kiesik a játékból.

Teremteni szeretnék egy lehetőséget, hogy ilyen szabályokat lehessen mondani:

\ClassLoader::import('PHP\Lang\*');
Ezzel viszont az a probléma, hogy a * miatt betöltött fájlban is lehet ugyanilyen szabály. Hogyan tudnám megoldani, hogy a kötelező sorrendek be legyenek tartva a betöltésnél? (pl. szülőosztály betöltése)

Ötletek, amiket Tyr43ltől kaptam a probléma megoldására:

  • Reflectionnel nézzük végig betöltéskor az osztályt, hogy milyen függőségei vannak. Így csak az indulást lesz lassú.
  • Induláskor húzzunk fel egy autoloadert a dependenciák feloldására.


A projekt SVN repója itt található: http://svn.janoszen.com/repos/fw/trunk/framework/
A generált doksik pedig itt: http://svn.janoszen.com/docs/fw/framework/
(A kód egyelőre működésképtelen, proof-of-concept gyártása van folyamatban, pár demó kódot gyártottam benne.)

Köszönöm a segítséget.
 
1

hogy idezzem magam: hat

Tyrael · 2011. Feb. 11. (P), 00.52
hogy idezzem magam:
hat futasidoben lehetne tokenizert vagy reflectiont hasznalni a dependenciak felderitesere, de az ***** lassu lenne, bar ha daemon, akkor az indulas lehetne lassu
de akkor meg mindig az a kevesbe gany megoldas, hogy felhuzod az autoloadert, betoltesz butan mindent, az autoloader feloldja a dependenciakat, majd ha felhuztal minden fajlt, akkor leszeded az autoloadert

utolag belegondolva a Reflection-os valszeg nem jo, ha nem tudod betolteni a class definiciot, akkor nem fogod tudni Reflection-nel lekerdezni sem hogy mibol van szarmaztatva, mit implemental, etc.

Tyrael
2

Egyszer régen... és egy jól működő

Pred · 2011. Feb. 11. (P), 01.13
Edit: újra elolvasva a felvetésed, lehet, hogy be is néztem a választ :$

Egy lehetséges megoldás (csak elmélet):
Fejlesztés után egy scriptet ráeregetni a kódbázisra, ami meghatározza a függőségeket és azokat tárolja valahol (Az extends és implements alapján, valamint a ClassLoader::import hívások feldolgozásával). A probléma a változókkal lesz. Pl: ClassLoader::import('PHP/'.$module.'/*')
Betöltésnél ezen adatok alapján indulhat egy rekurzív csoda, ami elkezdi feltérképezni a függőségeket és betölti a fájlokat.
Ha jól strukturáltak a fájlok, akkor a * és egyebek szépen feldolgozhatók regexp-el, ezáltal a betöltendő osztályok listája is előállítható.


Az eredeti:

Régebben próbálkoztunk mi is hasonlóval, bár a megközelítés kicsit más volt.

Röviden az alap koncepció:
Mindig van autoloader a biztonság kedvéért.
Minden futásnál ellenőrizzük, hogy a kérés paraméterei alapján tárolunk-e infót.
Először semmilyen infó sem áll rendelkezésre a szükséges fájlokról. A futás végén a kérés adatai alapján egy azonosítót hozunk létre és ehhez tároljuk, hogy milyen fájlok lettek betöltve.
A következő futásnál már az azonosító alapján ismert a fájllista amit be kell tölteni.

Az autoloader mindig ott van, hogy ha valami olyan ágba kerülünk, ami eleddig nem szerepelt, akkor is beölthessük az osztályt.

Egy másik sokkal jobban működő (az ötlet nem az enyém, de itt a helye):
Maga a FW egy külön project / repó, amiben szépen struktúrált fájlok vannak. Módosítást ezekben kell végezni. Deploy-nál a fájlokat egy nagy fájlba fésüljük össze -> eredmény egy nagy fájl, ami a core-t tartalmazza.

Minden további project ezt a generált fájlt használja, valamint az autoloader a project specifikus osztályokat (helper, controller, view, stb) ez alapján tölti be.


Egy észrevétel a tiedhez:
A tokenizálás és a kód feldolgozása több erőforrást fog felemészteni, mint az autoloader. E nélkül pedig vagy tudnod kell, hogy milyen osztályokra van szükséged, amit nem tudsz a fájl betöltéséig.
Mindazonáltal kétségtelen, hogy remek fejtörő :)
3

Jó lenne.

janoszen · 2011. Feb. 11. (P), 07.52
A megoldás jó lenne, mivel változóval megadott importok nincsenek, de a generálást szeretném elkerülni.

Az erőforrások felemésztése egyébként nem gond, max a daemon indulása tart sokáig.
4

Miért nem preg_match?

Eddie · 2011. Feb. 11. (P), 09.59
Minek ehhez tokenizer, meg reflection?
Mivel a cél ha jól látom a java féle includeolás, ezért erre nagyon egyszerű regexpet írni. És erre akkor születhet egy rekurzív függvény, ami mielőtt includeolna egy filet, includeolja annak a depencenciáit. A körkörös hivatkozások feloldására esetleg lehet belerakni egy maximum rekurziós mélységet.

function myrequire($file, $depth=0) {
    if ($depth > 20) return false;
    if (!is_readable($file)) return false;
    $fc = file_get_contents($file);
    preg_match_all('/\s*new\s*(\w+)/ims', $fc, $matches);
    $missingClass = false;
    foreach($matches[1] as $class) {
        if (!class_exists($class)) {
            if !(myrequire($class.'.php', ++$depth)) return false;
            if (!class_exists($class)) {
                $missingClass = true;
            }
        }
    }
    if(!$missingClass) {
        include($file);
        return true;
    } else {
        return false;
    }
}
5

aki ert a regexhez, az

Tyrael · 2011. Feb. 11. (P), 14.50
aki ert a regexhez, az onnantol mindent formalis nyelvnek nez. :/
ugye lehetnek olyan hivatkozasok is, amiket a new szora kereses nem fed fel (fuggveny-re, valtozora, konstans-ra hivatkozas, indirekt hivatkozas (akar call_user_func* akar $variable() formaban)).
ezert tamogatnam azt, hogy a php parseolasat bizzuk a php-ra, es toltsuk be a hianyzo dependenciakat autoloaderrel, amit akar az indulas/minden class betoltese utan spl_autoload_unregister -rel le is lehet szedni, de ha ugyis felhuztunk minden class-t, akkor sosem fog meghivodni (ha megis, akkor igazabol jobb, hogy az autoloader szakitja meg a script futasat, mint ha a php dob egybol class not found hibat)

Tyrael
6

Megoldva

janoszen · 2011. Feb. 11. (P), 20.49
Nos, megoldottam a dolgot. Azt csináltam, hogy az importált fájlokból egy load queuet toltam be, aminek az elejére toltam be az új osztályokat. A csillagos szabályok feloldásakor előállt fájl listát ellenőriztem és csak azokat toltam be, amik még nem szerepeltek sehol. Így remélhetőleg sikerült mindenféle dependenciát megoldani. A megoldás nemsokára ott lesz a repóban.