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\RobotLoader. 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é ![]()
Komentáře
» přidat
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře ani hlasovat

#1 rADo http://radekhulan.cz/ nový
Co podpora pro PHP 4.x?
#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ýmclass 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.
#3 medden michal.sustr@gmail.com nový
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é
#4 Honza V. nový
Doprkýnka, to je tak strašně jednoduchý a přitom naprosto geniální, že mě to nenapadlo dřív…
#5 Honza V. nový
Jo, nechceš už dát ke stažení aspoň ten modul, co umí tady tohlencto?
#6 medden michal.sustr@gmail.com nový
#3 medden:
No ten príklad mal byť takto:
Skúsil som si spraviť benchmark (predpokladám, že používaš parse_ini_file) a bol som šoknutý:
INI: avg = 0.00327613067627 dev = 0.000486483699644
<br />PHP: avg = 0.00415405726433 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ý.
#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.
#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äť?
#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 :)
#10 halogan http://halogan.blog.lupa.cz nový
#9 Pavel: Mohu se zeptat, ktery framework Vas oslnil?
#11 medden michal.sustr@gmail.com 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 …
#12 Jakub Podhorský jakub.podhorsky@centrum.cz 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 :)
#13 johno http://johno.jsmf.net/ nový
#11 medden: No ešteže tak.
DGX: Čo ak niekto používa
autoloadvo svojej/inej knižnici? Na to si myslel?#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 :)
#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?
#16 llook http://llook.wz.cz/weblog/ nový
#13 johno: To by mělo být jednoduchý – prostě se v té knihovně
__autoloadzakomentuje 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.
#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ť.
#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 ;)
#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é
__autoloaddále rozšířit, neboť Nette::autoload vrací boolean, nevidím v tom žádný problém:#20 bleak bleak@atlas.cz 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.
#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… :)
#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
#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.
#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 :)
#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 :(
#26 Pavel nový
Why I hate frameworks – :)
#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?
#28 David Grudl http://davidgrudl.com nový
#27 Filda: jistě, to by způsobilo Fatal error: Cannot redeclare class XXX
#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:
Dá se to řešit vzorem Factory, ale ne u cizích knihoven.
#30 BoneFlute BoneFlute@seznam.cz 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() `.
#31 noone nový
A kdy bude nette venku
#32 a3x nový
Nemáte skúsenosti s IDE EngInSite PHP Editor? Ako by obstál v konkurencii?