Přejít k navigační liště

Zdroják » PHP » Nette Framework: adresářová struktura aplikace

Nette Framework: adresářová struktura aplikace

Články PHP, Různé

Pokračujeme s aplikací Automat na kávu a zaměříme se na její adresářovou strukturu. K čemu slouží zaváděcí soubor a jak souvisí Nette Framework se životním prostředím? Lze dát sbohem příkazu require_once?

Pojďme se podívat podrobněji na adresářovou strukturu a jednotlivé soubory aplikace Automat na kávu (ke stažení na konci článku). Celý projekt je rozdělen do tří adresářů:

  • app  – obsahuje všechny soubory serverové části aplikace
  • libs  – obsahuje knihovny třetích stran, mohou být společné pro více aplikací
  • document_root  – kořenový adresář dostupný přes prohlížeč

Jakýkoliv požadavek na HTTP server je směrován dovnitř adresáře document_root. Zde se nacházejí všechny obrázky, kaskádové styly, javascriptové soubory. A také soubor index.php, přes který vedou všechny požadavky na HTML stránky. Pokud bychom používali tzv. Cool URL, vytvořili bychom pravidlo mod_rewrite, které by opět všechny požadavky na stránku nasměrovalo skrz index.php.

Přičemž index.php nedelá nic jiného, než že definuje cesty k ostatním dvou adresářům app a libs (jako konstanty) a předá řízení zaváděcímu souboru aplikace.

define('WWW_DIR', dirname(__FILE__)); // path to the web root
define('APP_DIR', WWW_DIR . '/../app'); // path to the application root
define('LIBS_DIR', WWW_DIR . '/../libs'); // path to the libraries

require APP_DIR . '/bootstrap.php'; // load bootstrap file 

Pojmenování a umístění jednotlivých adresářů je zcela ve vaší režii. Pokud preferujete jiné konvence, račte si je dopřát. Stačí jen změnit cesty v  index.php a aplikace dál poběží, jako by se nechumelilo. Nezapomeňte dohlédnout na to, aby adresáře aplikace a knihoven byly nepřístupné z webového prohlížeče. Například pomocí pravidel v souboru  .htaccess:

Order Allow,Deny
Deny from all 

Zaváděcí soubor

Zaváděcí soubor app/bootstrap.php nejprve vykoná nám již známé operace. Načte framework, aktivuje Laděnku a pro jistotu zkontroluje, zda lze zapisovat do adresáře pro dočasné soubory.

// Krok 1: Načtení Nette Framework
require LIBS_DIR . '/Nette/loader.php';

// Krok 2: Konfigurace prostředí
// 2a) zapne NetteDebug pro lepší vizualizaci a zpracování chyb
Debug::enable();

// 2b) kontrola, zda je složka /app/temp zapisovatelná
if (@file_put_contents(Environment::expand('%tempDir%/_check'), '') === FALSE) {
        throw new Exception("Make directory '" . Environment::getVariable('tempDir') . "' writable!");
} 

Poté následuje nastavení routeru a samotné spuštění aplikace. Zatímco routování je kapitolou samo o sobě (tedy alespoň z pohledu tohoto seriálu), o třídě NetteEnviron­ment, jejíž jméno v ukázce zdrojového kódu padlo, si něco povíme hned.

Třída Environment

Kladnozelený vztah Nette Frameworku k životnímu prostředí webové aplikace signalizuje skutečnost, že si nevytváří žádné globální proměnné nebo konstanty. Celé prostředí má pod palcem statická třída NetteEnviron­ment. Ta slouží jako globální úložiště pro:

  • proměnné prostředí (obvykle cesty, třeba k dočasnému adresáři)
  • název a režimy prostředí
  • konfiguraci aplikace
  • singletony

Proměnné prostředí lze nastavit a získat pomocí těchto dvou metod:

// pokud používáte verzi pro PHP 5.3, odkomentujte následující řádek:
// use NetteEnvironment;

Environment::setVariable('foo', 'Hello World');
echo Environment::getVariable('foo'); // -> Hello World 

Framework zjednoduší provázání i na konstanty definované v souboru index.php. Pokud například požádáte o nedefinovanou proměnnou appDir, zkusí se podívat, jestli neexistuje konstanta APP_DIR a vrátit její hodnotu. Hlavní výhoda tohoto řešení se projeví při využití další vlastnosti konstant, a tou je rozvíjení.

// mezi znaky % je název konstanty
Environment::setVariable('foo', 'Rozvíjej se %poupatko%');
Environment::setVariable('poupatko', 'programátore');
echo Environment::getVariable('foo'); // -> Rozvíjej se programátore 

Díky tomu je možné definovat jako proměnné absolutní cesty, ačkoliv známe jen cestu relativní. Například jako dočasný adresář chceme nastavit app/temp, ale absolutní cestu k app  neznáme (tu definuje index.php konstatnou APP_DIR). Lze však nastavit:

Environment::setVariable('tempDir', '%appDir%/temp');
echo Environment::getVariable('tempDir');
// -> vypíše absolutní cestu, neboť nahradí %appDir% za konstantu APP_DIR 

Pro rozvinutí proměnné bez její definice lze použít metodu expand, jak toho využívá kód v  bootstrap.php ověřující, zda lze do dočasného adresáře zapisovat.

Sbohem všem require dej

PHP disponuje čtyřmi příkazy pro načtení skriptu z jiného souboru. Tedy require, include a jejich sourozenci s koncovkou _once. Pokud je cesta k souboru relativní, dohledává se skript mně naprosto nepochopitelným způsobem, proto také poučení programátoři používají cesty absolutní. A jelikož magická konstanta __DIR__ přijde až s PHP 5.3, hromadí se na začátcích souborů haldy něčeho takového:

require_once dirname(__FILE__) . '/libs/ClassA.php';
require_once dirname(__FILE__) . '/libs/ClassB.php';
require_once dirname(__FILE__) . '/libs/ClassC.php';
... 

Z estetického hlediska jde o zástupce ASCII art deco, povšimněte si zvláště půvabného spojení závorek s podtržítky. V odborných kruzích však podobné obrazy nesou název „Serverova smrt“ a společně s výjevem Hieronyma Bosche „.htaccess obsahující 486 pravidel RewriteRule“ se jimi straší malé, čerstvě vylíhlé, revize Apache.

Skutečně se ukazuje, že jedním z největších zabijáků výkonu PHP je načítání velkého množství souborů (navíc nejsou-li absolutně adresováné). Co se s tím dá dělat? Účinnou zbraní je kompaktní minimalizovaná verze frameworku, viz první díl seriálu. Díky ní celý Nette Framework načtete jedním jediným příkazem:

require 'Nette/loader.php'; 

Pokud ale minimalizované verze nejsou k dispozici nebo by jejich použití nebylo vhodné, dá se dosáhnout velké úspory výkonu tím, že budeme načítat pouze soubory, které skutečně potřebujeme. A tomu slouží autoloading.

Nutno říci, že zvýšení výkonu aplikací je pouze druhotným efektem autoloadingu. Prim drží pohodlí, které s ním programátor získá. Bude moci přestat používat příkaz require a velmi rychle zjístí, jak je to návykové.

Autoloading zajišťuje obslužná funkce, která jako parametr dostane jméno třídy/interface a jejím úkolem je načíst skript s definicí. Otázkou zůstává, jak obecně odvodit z názvu třídy jméno souboru?

(Poznámka: špatně napsaný autoloadovací handler může vést k citelnému snížení výkonu aplikace.)

(Poznámka č.2: vyšší zátěž serverů vede ke globálnímu oteplování serverovny.)

RobotLoader

Třída NetteLoadersRobotLoader na to jde způsobem, který znáte od vyhledávačů. Podobně jako roboti vyhledávačů procházejí a indexují všechny stránky, tak i RobotLoader prochází všechny PHP skripty a zaznamenává si, které třídy a rozhraní v nich našel. Výsledky bádání si poté uloží do cache a použije při dalším HTTP požadavku. Stačí tedy určit, které adresáře má procházet (předpokládejme, že cesty se nacházejí v konstantách APP_DIRLIBS_DIR):

Následující řádky je možné přidat do zaváděcího souboru bootstrap.php a poté lze odstranit všechny require_once použité v aplikaci.

// pokud používáte verzi pro PHP 5.3, odkomentujte následující řádek:
// use NetteLoadersRobotLoader;

$loader = new RobotLoader();
$loader->addDirectory(APP_DIR);
$loader->addDirectory(LIBS_DIR);
$loader->register(); 

Pokud byste chtěli využít služeb RobotLoaderu mimo MVP aplikace Nette, je potřeba nastavit cestu k dočasnému adresáři do proměnné prostředí  tempDir:

Environment::setVariable('tempDir', '/absolutní/cesta/k/temp'); 

RobotLoader pracuje s cache inteligentně. Při vytvoření nové třídy ji invaliduje a zároveň si pamatuje, které třídy v adresářové struktuře nenašel. Můžete tedy pohodlně rozvíjet svou aplikaci a RobotLoader vám v tom bude sekundovat.

Ještě perlička na závěr: pokud byste chtěli určitý podadresář z indexování vynechat, vytvořte soubor netterobots.txt se známou syntaxí:

Disallow: Zend 
Zdrojový kód ukázek je k dispozici ke stažení.

Pokračování příště

Příště nás čeká atraktivní téma: JavaScript, AJAX a bohaté aplikace.


Autor článku je vývojář na volné noze, specializuje se na návrh a programování moderních webových aplikací. Pravidelně pořádá školení pro tvůrce webových aplikací, vyvíjí open-source knihovny Texy, dibi a Nette Framework.

Komentáře

Subscribe
Upozornit na
guest
42 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Mastodont

Přičemž index.php nedelá nic jiného, než že definuje cesty k ostatním dvou adresářům app a libs (jako konstanty) a předá řízení zaváděcímu souboru aplikace.

require APP_DIR . '/bootstrap.php'; // load bootstrap file

Velmi podobně vypadá index.php i ve WordPressu. Čistě náhodou by ty dva soubory sloučit nešly?

Martin Malý

Kdysi se slučovalo až tak extrémně, že v index.php bylo všecko… :) Jinak – je to otázka "rozumné meze", kterou má každý programátor někde jinde. IMO je rozumné mít v index.php opravdu jen to nejnutnější, tedy cesty, základní include a nějaké main(); Něco jako býval stub.obj, kdo ho pamatujete :)

Mastodont

Ano, třeba sNews bývaly složeny z jednoho souboru – a jaká to byla pohoda. IMHO by v index.php mělo být vše, co je potřeba ve 100 % případů, čili například kontrola toho, zda je web ve stavu offline nebo online, kontrola blokace IP adresy (pokud je) apod. … mít 100 tříd ve 100 souborech je zběsilost :-)

Martin Malý

Nejsme v rozporu… Tohle jsou věci, které (společně třeba s načtením application.ini) dávám do index.php taky

Jiří Knesl

Jistě, sloučit by šly.

Já třeba většinou mám bootstrap a index sloučený (když píšu v Zendu nebo Nette).

Záleží na povaze frameworku, někde si skládáte strukturu sám (Zend, Nette) a tam si píšete index i bootstrap – pak to můžete sloučit (když k tomu máte důvod). V jiném frameworku (CakePHP, Code Igniter) dostáváte sktrukturu předvyplněnou a tam se bootstrap.php hodí.

Martin Malý

Trošku kacířskou otázku položím: Nette je malý a jednoduchý framework, že? Proč je tedy jeho autoloader takto mocný, indexující a cachující? Nevystačil by si s autoloaderem postaveným na jednoznačné jmenné konvenci, kdy z názvu třídy lze odvodit jméno souboru i jeho umístění? Či jinými slovy: Proč zrovna tady nedrží princip "convention over configuration"?

aprilchild

Ja bych rekl, ze je to tak napul. Na jedne strane to umozni vytvorit si vlastni konvenci, mit v jednom souboru vice trid a suplovat tim spise funkci "modulu". Je to otazka vkusu, ale nekomu vyhovuje vice abstrakce "soubor = modul" oproti "soubor = trida" (dekujeme Jave..). Ovsem je pravdou, ze tahle benevolence povede u neporadnych programatoru k totalnimu chaosu v pojmenovani a lepe by se hodila konvence jednoznacna. Idealne bych asi pouzival konvenci, soucasny zpusob by musel byt nekde explicitne povolen.

Mozna lepsi vice souboru, nez neporadek pri prebirani ciziho projektu.

Martin Malý

Jmenná konvence nebrání mít v jednom souboru víc tříd… jen se musí podobně jmenovat. :)

Martin Malý

Knihovnám třetích stran lze udělat wrapper třídu, která dodrží jmennou konvenci, načte si vše co je potřeba a odkud je to potřeba, a hlavně funguje konzistentně se zbytkem systému. Ano, je to vrstva navíc, ale není to tak tragické; navíc si člověk pro knihovny třetích stran často dělá nějaké "přiohýbací" metody, takže se mu ten wrapper stejně hodí.

"Nesetkal jsem se s nikým, kdo by třídy aplikace pojmenovával…" – a to já zas jo. Právě proto je to "jmenná konvence", protože určuje, jak se třída má jmenovat. "Donutit" programátora pojmenovat třídu jako Model_Automat sice omezuje jeho kreativitu ve vymýšlení názvů, ale oba víme, že kreativita zrovna tady občas i škodí – právě i z důvodu (dosavadní) neexistence jmenných prostorů. ;)

Martin Malý

OK. Já se ptám proto, že jsem se při vývoji vlastního FW propracoval právě od systému "prohledám-a-najdu" ke "konvenci vím-kde-to-hledat" a připadá mi pohodlnější, rychlejší a víc sexy. Takže teď dumám, jestli jsem nepřehlídnul nějaký problém…

v6ak

Ne, že by mě vrstva navíc nenapadla, ale považuju to za špatné řešení. Nevím, co si pod tím přesně představujete, ale v každém případě to způsobí jednostrannou nebo žádnou kompatibilitu s ostatními.
Samozřejmě, to se týká jakéhokoli wrapperu, který neimplementuje původní rozhraní, vč. Dibi. Nezavrhuju všechny wrappery, ale pouze ty, kde přínos není dostatečný k ospravedlnění ztráty kompatibility.

Martin Malý

Tak, že do řetězce "Framework – 3rd party knihovna" je přidán mezičlánek "Framework – Wrapper pro knihovnu – 3rd party knihovna". Wrapper tu má roli prostředníka, který odstiňuje aplikačního programátora od API knihovny a "zapouzdřuje" ji do formátu a zvyklostí podle zbytku frameworku, tedy tak, že "navenek" dodržuje např. tu jmennou konvenci a (např.) usnadňuje změny kódu při změně knihovny. Příklad: Používám CAPTCHA. Udělám si tedy "wrapper" třídu, která se tváří jako integrální součást frameworku a poskytuje metody tak, jak je uživatel frameworku zvyklý, ovšem "uvnitř" zajišťuje funkcionalitu voláním nějakých knihoven třetí strany (recaptchalib např.)

v6ak

To je ta přínosnější i drastičtější varianta.
Ještě jsem zapoměl na jedno měřítko: práce cizích knihoven s tím. Třeba v případě CAPTCHA knihoven:
1. Mohou implementovat jedno rozhraní => přínos v polymorfismu
2. Moc knihoven s nimi nebude pracovat
Jako protiklad bych uvedl wrapper pro kolekce, který by měl vlastní rozhraní. Jakkoli by to bylo přínosné (IMHO minimálně), bylo by to nekompatibilní s čímkoli ostatním.

Martin Malý

Mám intenzivní dojem, že každý mluvíme o něčem jiném. Každopádně u čtvrtého "knihoven" jsem se ztratil, nechápaje kdo s kým nebude pracovat a proč. Řekl bych, že to asi není podstatné a že už zabíháme do detailů, do nichž jsem zabřednout nechtěl.

Jiří Knesl

A to je právě ono. Třeba se mi nepodařilo skloubit do sebe autoloader DomPDF a Zend Frameworku. A přitom stačí použít Nette RobotLoader, který tento problém řeší i bez wrapperu.

Martin Malý

Pokud má knihovna vlastní nekompatibilní autoloader, pak opravdu můžu jmennou konvenci zahodit. Ale na začátku tohoto vlákna jsem se ptal, proč David použil toto řešení v Nette, nikoli "co dělat, když má includovaná knihovna vlastní autoloader". Pokud chci připojit obrovskou knihovnu s vlastním autoloaderem do svého FW, tak je IMHO ideální řešení zapojit pořádně hlavu a trochu se v tom povrtat, než se spoléhat na loadery…

v6ak

Stačí dodržovat některé z pravidel, které jsem psal na http://v6ak.profitux.cz/clanky/jak-by-mel-vypadat-kazdy-autoload.php (ne všechny) a nebude problém – použijí se dva autoloady.

yeah

Skutečně se ukazuje, že jedním z největších zabijáků výkonu PHP je načítání velkého množství souborů (navíc nejsou-li absolutně adresováné).

To by mělo být v php6 vyřešeno, ne? Ostatně tohle mi přijde pro php momentálně jako největší ostuda. Místo toho aby se řešil výkon tak se vymýšlejí ptákoviny, které do jazyka ještě dostat. A servery mezitim trpí třikrát větším náporem než musí…

hejhula

Máme rok 2014 a kde je PHP6? :-D
Nikde…. Kdyby se ti amatéři vysrali na psaní pokusu o programovací jazyk, všem programátorům by se žilo lépe.

Borek Bernard

Jak Nette řeší víc konfigurací, např. jednu pro testovací prostředí a jednu pro reálný provoz?

Borek Bernard

Elegantní, díky za odpověď.

Pavel Voska

To je pěkné řešení, nabízí se ale otázka, zda zpracováním INI souboru (předpokládám že při každém requestu) není zbytečný overhead, resp. zda by nějaké Array řešení nebylo u více zatížených aplikací rychlejší. Nebo se pletu a otevření, zparsování a interpretace syntaxe nemají na rychlost vliv?

tomik.vitek

Ono se vpodstatě jedná o asociativní pole. ;)

Je to parsované parse_ini_file (http://cz2.php.net/parse_ini_file), což je parser PHP pro php.ini, je tedy již zkompilovaný a VELMI rychlý.

Srigi

To je zaujimavy vysledok. V Docbook pre FW Symfony mozno najst az "chvalenkarstvo", ze ich FW konfiguraky kompiluje a je preto rychly.

Ale Symfony vyuziva YAML konfiguraky a po celej zakladnej aplikacii su ich takmer dve desiatky, takze tam to asi zmysel ma.
Kompiluju ich do PHP poli.

Miloslav Pojman

Autoload je sexy, zvlášť jak je implementován v nette. Ve výsledku mi ale přijde kontraproduktivní, protože zdrojový kód ztrácí rychle na přehlednosti.

Těch několik require_once na začátku každého souboru jasně popisuje závislosti – hned vidím co se používá a odkud se to bere. Pokud musím prohledat všechny soubory, abych zjistil odkud se symbol (ať je to globální proměná, funkce nebo třída) bere, je něco špatně.

Snad každý jazyk používý nějaký konstrukt pro import, include nebo podobně. A zřejmě to nebude proto, že by jeho vývojáři neuměli napsat nějaký autoload.

Mimochodem, proč všichni pro include používají nejrůznější konstrukce jako dirname(__FILE__) nebo NEJAKA_KONSTANTA_BASE_PATH, když tu máme include_path?

v6ak

Dodal bych, že v Javě není import povinný – při odkázáni se na třídu je možné uvést namespace a při práci s návratovou hodnotou ani to. V php to asi bude podobně.
V Javě je při použití více tříd se stejným názvem někdy potřeba použít namespace.Třída, v php se tomu snad půjde vyhnout přejmenováním. Ale těžko se vyhnu přímo práci s návratovou hodnotou. Ale to zas tak nevadí.
Jinak java v podstatě má autoloading.
Lehké ot: jak php 5.3 vyřeší odkazy na ReflectionClass? Bude možné něco jako Třída.class, nebo bude potřeba použít řetězec s celou cestou a případnými problémy při refaktoringu?

Miloslav Pojman

To je dobrý postřeh. Ale má smysl přehlednost vykoupit značným dopadem na výkon aplikace?

Co jsem sledoval nějaké diskuse ohledně vývoje zend frameworku, tak ten dopad na výkon je skutečně znatelný. Ale:

  • Nette má kompaktní verzi, kterou použiju, pokud mi jde o výkon, kde žádné include nebo autoload neřeším.
  • Když použiju knihovnu třetí strany, ta si řeší includy po svém a na autoload stejně nedojde
  • Pokud si napíšu vlastní knihovnu, nechci aby byla závislá na nette a jejím autoloadu
  • Vlastní skripty pro jednotlivé stránky jsou zpravidla jednoduché a jedou vždy po stejné koleji, takže zbytečné includy moc nehrozí. Pokud používám nějakou složitou knihovnu, kterou využiju jen občas, můžu v jejím připadě includovat až když ji opravdu potřebuji.

Osvědčil se mi jiný postup. Nette je plně připravené na PHP 5.3 a jmenné prostory. S jejich použitím dojde k tomu, že se na začátku skriptů budou objevovat řady příkazů use (méně elegantní ASCII art deco ;-) ). Něco jako když se dnes člověk podívá na zdroják v C#. Na výkon to dopad nemá, ale jako dokumentační popis závislostí to funguje stejně dobře, ne-li lépe. No a já jsem si zvykl tyto příkazy, byť zakomentované, používat už v PHP 5.2.

Ale kolik vývojářů používajících nette dodržuje stejné konvence?

Ať si každá knihovna nebo framework uvnitř používá co chce. Nelíbí se mi ale vydávat autoload na všechno za standardní řešení (jak se může po přečtění zdát začínajícímu programátorovi). Autoload má v mnoha případech smysl, ale každý vývojář by měl vědět proč a kde ho použít.

Na include_path teoreticky není 100% spoleh, je to pomalé a vyžaduje to od vývojáře, který chce použít knihovnu, aby správně include_path nastavil. Dovedu si představit, že třeba u takového Texy by půlka vláken na fóru byla: „nejede mi to“ s odpovědí „nastavil jsi správně include_path“?

Tohle jde například řešit pomocí souboru TexyForDummies.php, který nastaví příslušnou include_path a naincluduje Texy.php

Pokročilý vývojář si nastaví include_path jak potřebuje a použije standardní řešení.

U texy je to asi jedno, beztak můžu použít kompaktní verzi, ale používat deset knihoven, kde si každá řeší includovaní souborů nějakým obskurním způsobem je peklo. Autor každé z těch knihoven se bude hádat, že jeho řešení je nejlepší a těžko říct kde je pravda.

Když už jsem si jednou jsem si vybral php, tak preferuji řešení, které mi nabízí.

Miloslav Pojman

Nelíbí se mi ale vydávat autoload na všechno za standardní řešení.

Mně také ne.

Ani tě z ničeho takového nepodezřívám. Proto jsem psal „jak se může po přečtění zdát začínajícímu programátorovi“. Viz třeba „Sbohem všem require dej“ Samozřejmě je to nadsázka, ale článek mi tak vyznívá.

Ale přece include_path není „standardní řešení“, nebo alespoň není „standardnější“ než „standardní“ autoloading. Prostě je to jedna z cest. A pokud mohu aplikaci napsat tak, aby její funkčnost nebyla podmíněna správným nastavením určité direktivy, tak ji tak napíšu. Nerozumím snaze mě přesvědčit, abych tam uměle tuto závislost vložil ;)

Můje první větička o include_path byla trochu mimo téma. Nebyla to vítka proti Nette ani Texy. Jenom takový postesk, proč všichni používájí require_once SOME_CONSTANT . „foo/bar.php“ místo aby jednoduše přidali SOME_CONSTANT do include_path.

Souhlasím, že třeba závislost Texy na include_path je zbytečná.

Na druhou stranu includy v nette se mi už moc nelíbí. Asi je to otázka osobní preference, ale uvedu příklad (RobotLoader.php, přišel mi první pod ruku):

require_once 'Nette/Framework.php'; by mi přislo mnohem hezčí a hlavně přehlednější než require_once dirname(__FILE__) . '/../Framework.php';

Když se podívám dál, používají se v tom souboru třídy LimitedScope nebo Environment. Kde je mám hledat? Je zaručeno, že už byly includovány? Je tam schovaná závislost, kterou neobjevím, dokud neprojdu celý zdroják. Přitom zrovna závislost na Environment je hodně důležitá.

Jakub Vrána

Direktiva include_path má tu nevýhodu, že je nejednoznačná. Když napíšu include "compatibility.php", tak záleží na tom, v kterém adresáři z include_path se soubor najde jako první. Knihovna by si neměla dovolit direktivu sama přenastavit, protože když se přidá na začátek, tak mi přeplácne adresáře, ze kterých bych chtěl stejnojmenné soubory vkládat já, a když na konec, tak zase nemá jistotu, že se na ni dostane. Tím pádem je knihovna závislá na nastavení zvenku, což je otrava (a pořád zůstává problém se stejně pojmenovanými soubory v různých knihovnách).

Nezávislost na include_path je výhoda, nikoliv slabina.

Miloslav Pojman

Předpokládám, že svoji knihovnu mám v nějaké adresáři, takže píšu třeba include "moje_knihovna/compatibility.php" a konflikt by neměl nastat.

Aby si knihovna přidávala něco do include_path byl můj úlet, tak opravdu ne.

Dokud knihovna nemá žádné závislosti, tak trik s dirname funguje skvěle. A asi není důvod se ho pro includy v rámci knihovny vzdávat. Krom toho, že je to malinko méně přehledné, ale to je subjektivní. I když klukům v zendu to přijde asi stejně.

Neřeší mi to ale externí závislosti. Mám pro kažkou knihovnu kterou používám definovat nějakou konstantu?

Stejně jako každý jazyk má nějaký import nebo include, tak snad každý má nějakou importpath, classpath nebo podobně. Proč se jí zrovna v php bránit?

Jakub Vrána

Takže při adresářové struktuře libs/Nette by v include_path byl adresář libs? To mi ale zabraňuje si adresář pojmenovat jinak, třeba Nette-0.8. Opravdu nevidím žádný způsob, jak se vevnitř knihovny bez výpočtu cesty obejít.

V aplikaci, která knihovny využívá, mám svobodu – můžu používat relativní cesty, konstanty nebo klidně i include_path, ale vnitřek knihovny by se na to neměl spoléhat.

Miloslav Pojman

V knihovně zpravidla nejsou jenom zdrojáky, ale často také testy, nějaké demo, readme, lincense, atd… Samozřejmě většinu nepotřebuji, ale přinejmenším při vývoji chci ke knihovně i ty věci okolo.

Takže v adresáři lib (kterých může být několik) mám např. Nette-0.8 a v něm mimojiné podadresář Nette nebo případně source/Nette (jak to stáhnu). V include path pak Nette-0.8 respektive Nette-0.8/source. Ono neuškodí mít na jednom místě sepsané všechny použité knihovny.

Jakub Vrána

Vedle aplikace chci mít pouze samotnou knihovnu, tedy jenom adresář Nette. Ostatní věci okolo (testy, příklady, licenci, ikonky) mohu používat při vývoji, ale pro nasazení aplikace to není potřeba a nemělo by to tam tedy ani být.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.