Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

Translate to English… Ins Deutsche übersetzen…

Vkládání souborů v Nette

Programový kód zpřehledníme rozdělením do více souborů. V případě OOP se nabízí ukládání každé třídy/interface (resp. několika úzce souvisejících tříd) do samostatného souboru. Tyto soubory je vhodné pojmenovávat podle nějaké své konvence. Následně je vkládáme do skriptů konstrukcí require_once. Opět, kvůli přehlednosti, bývá zvykem všechna vkládání umísťovat na začátky skriptů.

Odbočka: pokud použijete relativní cestu k souboru, require_once jej dohledá možná trošku nečekaným způsobem. Na include_path se také nerad spoléhám, proto se kloním k používání absolutních cest tímto způsobem:

require_once dirname(__FILE__).'/soubor.php';

Slabá místa

Tohle všechno sice přispívá ke zpřehlednění kódu, ale má to i slabé stránky:

  • vkládáme soubory, které třeba nebudeme potřebovat
  • ke každé třídě si musíme pamatovat název souboru

Obzvláště ta dualita třída ↔ soubor mi hodně vadí. Hledal jsem tedy nějaké flexibilní řešení, které by jednak odstranilo obě slabá místa, zároveň co nejvíce zjednodušilo programátorovi život a hlavně nekladlo nová omezení či pravidla.

Řešení

Řešením je Nette\Loaders\Ro­botLoader. Základem je magická funkce __autoload. Díky ní se soubor s definicí třídy vloží až ve chvíli, kdy je skutečně potřeba.

Nette má vlastní obsluhu __autoload(). Jejím jádrem je vcelku jednoduchá funkce, která v adresáři webové aplikace proběhne všechny PHP skripty (tedy i podadresářích) a pomocí funkce token_get_all v nich vyhledá definice tříd a rozhraní. Výsledkem je tabulka identifikátorů a relativních cest k souborům. Nette pak přesně ví, který soubor při požadavku na konkrétní třidu vložit. Je to velice rychlé. Tabulka se samozřejmě uchovává v cache.

Při nahrání nové verze aplikace na web lze jedním příkazem tabulku vygenerovat znovu, nebo ještě jednodušeji – stačí smazat příslušný soubor a vygeneruje se sama.

aktualizace: Nette může běžet v tzv. vývojářském režimu (DEVELOPMENT). Pokud v tomto režimu není třída nalezena, provede se automaticky regenerace cache. Nepomůže-li to, ohlásí se error.

Výhody řešení

  • zbavíte se všech volání require_once
  • vkládají se jen potřebné soubory
  • bez striktních konvencí pojmenování souborů
  • možno mít více tříd v jednom souboru
  • není třeba ručně udržovat tabulku
  • Nette již při generování odhalí konflikty názvů
  • připadáte si jako v kompilovaném jazyce

Je to prostě velmi pohodlné a krutě návykové :-)

napsáno 22. 3. 2006 | shlédnuto 9269x | nahoru


Komentáře RSS 2.0 komentářů » přidat

avatar

#1 rADo http://radekhulan.cz/ nový

Co podpora pro PHP 4.x?

Posláno 22. 3. 2006 v 18.01 | Odpovědět
Na komentář reagoval [2] David Grudl [15] Ivan
avatar

#2 David Grudl http://davidgrudl.com nový

#1 rADo: Řeším to explicitním voláním __autoload. Například __autoload("BaseClass"); před každým class MyClass extends BaseClass {...} lze vložit automaticky PHP 5 → 4 převodníkem.

Pravda je, že teď, co mám na všech oblíbených hostinzích PHP5, tak jsem na podporu PHP4 vnitřně rezignoval. Tedy alespoň pro nové projekty. Tudíž tento návod klidně ber jako PHP5 only.

Posláno 22. 3. 2006 v 18.14 | Odpovědět
Na komentář reagoval [15] Ivan
avatar

#3 medden nový

Tabulka se samozřejmě uchovává na disku, v podobě INI souboru.

Takže si to dobre predstavujem, ak si myslím, že to bude takto? (ini súbor)
MenoTriedy = cesta
MenoTriedy2 = cesta2

Nebolo by potom jednoduchšie (a rýchlejšie) to nechávať v php súboroch? Mimochodom, vo svojom projekte používam niečo podobné :-)

Posláno 22. 3. 2006 v 18.22 | Odpovědět
Na komentář reagoval [6] medden

#4 Honza V. nový

Doprkýnka, to je tak strašně jednoduchý a přitom naprosto geniální, že mě to nenapadlo dřív…

Posláno 22. 3. 2006 v 18.29 | Odpovědět

#5 Honza V. nový

Jo, nechceš už dát ke stažení aspoň ten modul, co umí tady tohlencto?

Posláno 22. 3. 2006 v 18.32 | Odpovědět
avatar

#6 medden nový

#3 medden:
No ten príklad mal byť takto:

MenoTriedy = cesta
MenoTriedy2 = cesta2
…

Skúsil som si spraviť benchmark (predpokladám, že používaš parse_ini_file) a bol som šoknutý:

INI: avg = 0.00327613067­627 dev = 0.000486483699644<br />
PHP: avg = 0.00415405726­433 dev = 0.00078431006504

Použil som svoj php.ini súbor, mierne modifikovaný pre php použitie ;-), 1000 iterácií

Aj keď ono to je viac-menej pochopiteľné, prečo je ini rýchlejšie: php musí robiť aj syntatický rozbor a veci okolo toho… Ale aj tak som dosť prekvapený.

Posláno 22. 3. 2006 v 18.51 | Odpovědět
Na komentář reagoval [8] johno

#7 mrzout http://www.abclinuxu.cz/blog/mrzutej nový

Tenhle genialni postup jsem kdysi cetl v nejakem clanku a hned se mi zalibil. (mozna: http://www.sitepoint.com/…or-autoload/ )

Lze to vylepsit tak, aby __autoload pokud nenalezne v cache cestu k souboru, provede sam pokus o jeho dohledani v adresarove strukture a pokud ho nalezne, do cache doplni. Naopak i pri nalezeni testovat jeho existenci a pokud neni, z cache vyhodit.

Tim se uplne vypusti nutnost „pracne“ generovat cache.

Posláno 22. 3. 2006 v 19.22 | Odpovědět
Na komentář reagoval [14] Borek [18] David Grudl
avatar

#8 johno http://johno.jsmf.net/ nový

#6 medden: Prepáč, ale takéto testy sú na smiech. Kedy budeš parsovať 1000 ini súborov? A kedy ti tam bude vadiť ten rozdiel v tisícine sekundy? Oznamujem Ti, že robíš v zlom jazyku ak ti toto vadí.

Vieš koľko trvá napríklad zaslanie typického SELECTu do DB až po získanie dát naspäť?

Posláno 22. 3. 2006 ve 20.06 | Odpovědět
Na komentář reagoval [11] medden

#9 Pavel nový

Nechci byt protivny :), ale tento zpusob predstavovani Nette vedl jen k tomu, ze jsem zatim narazil na jiny framework, ktery se mi velice zalibil a ktery uz mohu zacit pouzivat na novem projektu… Takze popisy hezke, ale nakonec koncim u jineho :(

snad priste, pokud tou dobou jen nebude 50. dil povidani o Nette – coz doufam, ze ne :)

Posláno 22. 3. 2006 ve 20.43 | Odpovědět
Na komentář reagoval [10] halogan [20] bleak

#10 halogan http://halogan.blog.lupa.cz nový

#9 Pavel: Mohu se zeptat, ktery framework Vas oslnil?

Posláno 22. 3. 2006 ve 20.52 | Odpovědět
avatar

#11 medden nový

#8 johno: Mne je jasné, že tisícina sekundy je oproti iným veciam úplne zanedbateľná. Ja som sa pozastavoval iba nad tým, že parsovanie .ini pomocou štandartných funkcií je rýchlejšie ako parsovanie .php. Je mi jasné, že ak chcem niečo optimalizovať, tak sa musím zamerať na najslabšie (najpomalšie) časti, ako je zväčša databáza, a takýmito vecami vlastne strácam čas. Ja si to uvedomujem. No niekedy je dôležité poznať aj postupy, ktoré sú všeobecne rýchlejšie.

Viem, že Premature optimization is the root of all evil …

Posláno 22. 3. 2006 ve 21.08 | Odpovědět
Na komentář reagoval [13] johno
avatar

#12 Jakub Podhorský nový

pěkný řešení :) tohle mě nikdy nenapadlo…holt zkusím si s tím asi pohrát :) a nějak to zakomponovat do toho mojeho :)

Posláno 22. 3. 2006 ve 21.47 | Odpovědět
avatar

#13 johno http://johno.jsmf.net/ nový

#11 medden: No ešteže tak.

DGX: Čo ak niekto používa autoload vo svojej/inej knižnici? Na to si myslel?

Posláno 22. 3. 2006 ve 23.16 | Odpovědět
Na komentář reagoval [16] llook

#14 Borek http://borber.com/blog/ nový

#7 mrzout: To je určitě podstatné vylepšení, není moc dobré, když se musí ručně editovat něco, co může být uděláno automaticky. Zde ovšem výměnou za drobnou výkonnostní úlitbičku.

P.S. Dobrá captcha :)

Posláno 22. 3. 2006 ve 23.21 | Odpovědět

#15 Ivan nový

#1 rADo: #2 David Grudl: Taky bych nejraději na verzi 4 rezignoval, ale..

Bohužel nenalezení třídy vyhodí fatal error, tak to nelze obejít ani přes set_error_handler. Tak to taky řeším explicitně – v každé třídě napíšu co používá: Cl::req(‚Class1, Class2, Class3‘). A pak postup podobný tomu v článku. Nebyl by lepší nápad?

Posláno 23. 3. 2006 v 7.23 | Odpovědět
avatar

#16 llook http://llook.wz.cz/weblog/ nový

#13 johno: To by mělo být jednoduchý – prostě se v té knihovně __autoload zakomentuje a o načítání tříd knihovny se postará Nette.

Problém by mohl nastat, kdyby autoload té knihovny třídy neincludoval, ale vytvářel. Ale to bude asi velmi okrajový problém.

Posláno 23. 3. 2006 v 8.15 | Odpovědět
Na komentář reagoval [17] johno
avatar

#17 johno http://johno.jsmf.net/ nový

#16 llook: To je síce pekný nápad, ale nebude fungovať ak tá knižnica nie je v adresári, ktorý ten skript prehľadáva.

Možno by stálo za to tam dať ešte nejaký zoznam adresárov, ktoré má prehľadávať.

Posláno 23. 3. 2006 v 8.44 | Odpovědět
Na komentář reagoval [19] David Grudl
avatar

#18 David Grudl http://davidgrudl.com nový

llook to popisuje přesně, tento způsob je použitelný napříč knihovnami, proto je možné ostatní __autoload vyřadit.

#7 mrzout: wow, to je skutečně podobný způsob. Jen princip parsování přes regexp, ukládání do globální proměnné a používání absolutní cest jsou cestou zpět.

Pokud jde o znovuvytvoření cache pokaždé, když se třída nenajde, Nette to dělá, ale jen v ladícím režimu (doplnil jsem článek).

Jinak v praxi se mi ukázalo, že tabulku na hostingu nikdy negeneruji. Rovnou ji totiž s aktualizací webu překopíruju z lokálu – tím, že se ukládají jen relativní cesty, v tom není problém. Taktéž se nemusím bát nějakého „refactoringu“ na hostingu ;)

Posláno 23. 3. 2006 v 9.10 | Odpovědět
avatar

#19 David Grudl http://davidgrudl.com nový

#17 johno: je tam pevně daný kořenový adresář a seznam podadresářů k prohledávání (nemá třeba smysl prohledávat cache atd.)

Ale pokud to nevyhovuje, je možné __autoload dále rozšířit, neboť Nette::autoload vrací boolean, nevidím v tom žádný problém:

function __autoload($class)
{
    $result = Nette::autoload($class);
    if ($result == false)
        nejaky_jiny_autoload($class);
}
Posláno 23. 3. 2006 v 9.16 | Odpovědět
avatar

#20 bleak nový

#9 Pavel: Tento způsob představování Nette mne taky moc nebaví. Ale zrovna by se mi nějaký framework hodil – jsem amatérský příležitostný a líný tvůrce PHP skriptů.
Tak tedy také prosím Pavla o tip na framework, který začal používat.

Posláno 23. 3. 2006 v 9.23 | Odpovědět
Na komentář reagoval [21] FrozenDog [24] jules

#21 FrozenDog http://frozendog.blognito.sk nový

#20 bleak: len si pekne pockaj s nami ostatnymi. Mne uz tiez tecu sliny na klavesnicu vzdy ked vidim dalsi clanok o Nette (ako ten Pavlovov pes), ale vies aky to bude pocit, ked sa ti po vsetkych tych mukach dostane konecne Nette do ruk? Teda za predpokladu, ze bude naozaj take, ako sa teraz zda, vsakano… :)

Posláno 23. 3. 2006 ve 12.48 | Odpovědět

#22 error414 nový

Me by docela uspokojilo kdyby alespon napisal kolik procent uz toho ma napsano. Takhle to zni jako krasna pohadka (nechci tim rict ze nas DGX taha za nos).

Jestli tohle bude fungovat jak pises a nenarazi se na ostram provozu nejakou zasadni krpu, bude to super.

Bude treba nejake beta testovani?
Uz se moc tesim

Posláno 23. 3. 2006 v 15.08 | Odpovědět

#23 spud nový

Zajimavy reseni, jsem moc zvedavej na hotovy Nette. Zkusil jsem si udelat podle tvyho navodu univerzalni autoload … asi nebude tak genialni, ale treba se nekomu hodi, nez vytasis ten svuj komplet framework. :-)

Posláno 23. 3. 2006 v 15.27 | Odpovědět
avatar

#24 jules http://www.kapibara.sk nový

#20 bleak: pre rýchly vývoj webových aplikácií odporúčam CakePHP – framweork išpirovaný RubyOnRails, automatické generovanie editovateľných formularov – scaffolding, silná diskusná skupina, podpora php4, php5

stoji za pozretie http://framework.zend.com, zatial velmi cerstve…

zoznam frameworkov

a samozrejme – ocakavam nette :)

Posláno 24. 3. 2006 v 9.10 | Odpovědět
Na komentář reagoval [25] Pavel

#25 Pavel nový

#24 jules: ten seznam je nejaky oblibeny, prohlizel jsem ten samy :) kdyz jsem probral vsechny podminky, ktere musi byt splneny, vysel mi z toho CodeIgniter, na ktery momentalne koukam a ve volne chvili bych ho chtel zkusit.

Mozna ze i to Nette bude driv, to se neda vyloucit :) kazdopadne jak rikam, cele Nette me nakoplo jen k tomu, ze se koukam jinde :(

Posláno 29. 3. 2006 v 11.03 | Odpovědět

#26 Pavel nový

Posláno 30. 3. 2006 v 9.43 | Odpovědět

#27 Filda http://vobloz.xtr.cz nový

Takže jestli tomu dobře rozumim, tak v celym projektu nemůžou bejt dve ruzný třídy se stejným názvem?

Posláno 3. 4. 2006 v 16.29 | Odpovědět
Na komentář reagoval [28] David Grudl
avatar

#28 David Grudl http://davidgrudl.com nový

#27 Filda: jistě, to by způsobilo Fatal error: Cannot redeclare class XXX

Posláno 3. 4. 2006 v 16.37 | Odpovědět
Na komentář reagoval [29] llook
avatar

#29 llook http://llook.wz.cz/weblog/ nový

#28 David Grudl: Je fakt, že už jsem se párkrát s něčím podobným setkal:

if (phpversion() < 5) {
    require_once 'Trida_php4.php';
} else {
    require_once 'Trida_php5.php';
}

Dá se to řešit vzorem Factory, ale ne u cizích knihoven.

Posláno 3. 4. 2006 v 16.45 | Odpovědět
avatar

#30 BoneFlute nový

Mám dotaz. Pokud nahraji definici třídy až v okamžiku použití, platí to i na session?
Používám stále php4ku. A tam je nutné mít nahranou definici třídy dříve než se zavolá ` session_start() `.

Posláno 15. 4. 2006 ve 22.44 | Odpovědět

#31 noone nový

A kdy bude nette venku

Posláno 25. 5. 2006 ve 22.51 | Odpovědět

#32 a3x nový

Nemáte skúsenosti s IDE EngInSite PHP Editor? Ako by obstál v konkurencii?

Posláno 12. 10. 2006 v 16.01 | Odpovědět

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.

Výtah na začátek článku na první komentář

Názory čtenářů v diskusích nejsou názory provozovatele webu, a ten za jejich obsah neodpovídá.

phpFashion © 2004, 2012 David Grudlo webu

Pokud není uvedeno jinak, podléhá obsah těchto stránek licenci Creative Commons BY-NC-ND Creative Commons License BY-NC-ND

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.