Přeskočit na hlavní obsah

Direktiva include_path

Další ze základních konfiguračních direktiv je include_path. Slouží k nastavení základních cest, ve kterých se mají hledat soubory otevírané pomocí include a jemu podobných konstruktů a funkcí. V článku popisuji svůj pohled na její vhodné využití, zejména s ohledem na přenositelnost aplikace mezi různými servery.

Způsob postupného hledání otevíraného souboru popsal velice pěkně David Grudl v článku PHP triky: include, require a cesty. Všem doporučuji přečíst a postup vyhodnocování si ujasnit.

Direktiva include_path je v rámci tohoto mechanizmu velice užitečná. Nic se ale nemá přehánět. Neměli byste ji tedy zneužívat v krajním případě až pro nastavení všech cest do každého adresáře své aplikace. Optimální je určit cesty k základním knihovnám.

Zapomeňte na serverové nastavení

Bezproblémově přenositelná aplikace by si měla brát všechny využívané soubory s sebou. I když využívá nějakou obecně rozšířenou knihovnu, neměla by se nikdy spoléhat na to, že bude tato knihovna již na serveru nainstalovaná a zpřístupněná. Nedílnou součástí aplikace by tak vždy měly být i skripty všech používaných knihoven.

Z uvedeného vyplývá, že by aplikace vůbec neměla spoléhat na jakékoliv serverové nastavení include_path, tedy nastavení této direktivy v souboru php.ini. Pokud by na ně mělo dojít, je to neklamná známka špatně přenositelné aplikace.

Narozdíl od obvykle doporučovaných postupů se dokonce domnívám, že v aplikaci by se mělo serverové nastavení zcela zrušit a přepsat. Používám tedy vždy funkci set_include_path(), nepřipojuji na konec vůbec serverové nastavení získané z get_include_path().

Cesty definujte v aplikaci

Za základní a jediný rozumný způsob považuji výlučné použití funkce set_include_path() (před PHP 4.3.0 je nutno použít funkci ini_set()) přímo v kódu aplikace. Například u architektury využívající Front Controller se typicky definuje v bootstrap souboru.

Každopádně by se zde měly mapovat pouze adresáře skriptů distribuovaných přímo s danou aplikací a důsledně bez použití natvrdo daných absolutních cest. Jen tak lze zajistit snadnou přenositelnost mezi různými servery.

Pro oddělování jednotlivých adresářů je nutné používat zástupnou konstantu PATH_SEPARATOR, protože konkrétní oddělovací znak se na různých platformách liší. Výsledný předpis pak může vypadat nějak takto:

set_include_path(
    './library'
    . PATH_SEPARATOR . './application/model');

Aktuální pracovní adresář v include

Možná jste si všimli, že oproti běžně doporučovaným nastavením, na které jste asi zvyklí, mi zde kromě již výše zmíněného get_include_path() chybí na začátku cesty tečka pro aktuální pracovní adresář.

Osobně se na include_path spoléhám právě jen při načítání knihovních souborů. V Zend Frameworku pak navíc ještě pro načítání tříd modelu. Všechny ostatní případy řeším výslovným zadáním cesty, které vyřazuje include_path ze hry. Zvyšuje to rapidně čitelnost kódu, protože je hned na první pohled všem jasné, co jsem ve skutečnosti zamýšlel.

include './foo/bar.php';

Pokud tedy chci includovat nějaký soubor relativně k bootstrap souboru, pak přidám explicitní tečku přímo do daného include. K důslednému dodržování této praxe mne donutí právě nepřítomnost tečky v include_path, a tedy nemožnost se na ni implicitně spoléhat.

Absolutní cesty

Druhým případem je hledání oproti umístění skriptu, ve kterém je include umístěno. Tady sice include hledá úplně vždy, čili by se to teoreticky nemuselo vůbec řešit. Nicméně zde hledá až naposled, takže je zde riziko, že se místo něj použije některý stejnojmenný skript právě z include_path.

Nejjistější variantou tak je používat důsledně absolutní cestu. Aby ale byla aplikace přenosná, nelze psát absolutní cestu natvrdo, ale je nutné ji spočítat z konstanty __FILE__:

include dirname(__FILE__) . '/foo/bar.php';

Komentáře

  1. Když píšeš o tom, že aplikace by se neměla vůbec spoléhat na serverové nastavení včetně ZF nebo PEARu.
    To jako třeba s unit testy chceš distribuovat potřebené PEAR balíky a s každou aplikací postavenou na ZF distribuovat celý ZF? To se mi zdá poněkud zavádějící. IMHO stačí uvést, že aplikace je postavena na ZF 1.0.2 a tečka

  2. Jak napsal dgx href=„http://­latrine.dgx.cz/php-triky-include-require-a-cesty“ rel=„nofollow ugc“>http://la­trine.dgx.cz/php-triky-include-require-a-cesty na la trine, není třeba obalovat __FILE__ do dirname()…

  3. [1] Distribuovat skutečně netřeba. Ale to vůbec nesouvisí s tím, že je IMHO nevhodné používat jedinou sdílenou serverovou instalaci takové knihovny a výchozí serverové nastavení include_path. Měl jsem tu na toto téma delší reakci, ale vydá to nakonec na samostatný článek.

    [2] Obalovat to pomocí dirname() je přinejmenším dobrý a doporučeníhodný nápad. Je to čisté a systémové řešení, narozdíl od pouhého __FILE__. Nikdy nevíš, kdy se někdy v budoucnu nebo na nějaké specifické platformě změní způsob vyhodnocování realpath() – současné chování v tomto specifickém případě není AFAIK nikde zaručeno.

  4. Tak právě jsem zjistil, že nejnovější PHP 5.2.5 obsahuje závažnou chybu #43677 href=„http://­bugs.php.net/bug­.php?id=43677“ rel=„nofollow ugc“>http://bug­s.php.net/bug­.php?id=43677, kvůli které náhodně selhává direktiva include_path.

    Když brouzdáte na postiženém webu, tak prostě sem tam požadavek skončí chybou. Na této direktivě mimochodem stojí celý Zend Framework.

  5. Mrtvý článek, těšil jsem se, že si z něj něco odnesu, ale… buď je napsaný špatně, nebo nedokážu pochopit základní věci…

    „Možná jste si všimli, že oproti běžně doporučovaným nastavením, na které jste asi zvyklí, mi zde kromě již výše zmíněného get_include_path() chybí na začátku cesty tečka pro aktuální pracovní adresář.“

    Ve Vašem řešení chybí obvykle tečka, nebo v tom příkladě výše? (pokud se vůbec týká tohoto odstavečku) V příkladě totiž tečka na začátku cesty je…

    „Druhým případem je hledání oproti umístění skriptu, ve kterém je include umístěno. Tady sice include hledá úplně vždy, čili by se to teoreticky nemuselo vůbec řešit. Nicméně zde hledá až naposled, takže je zde riziko, že se místo něj použije některý stejnojmenný skript právě z include_path.“

    Tady/zde – opravdu není jasné, která místa máte na mysli…

    Napsal bych asi toto: Prvně je prohlédáváno oproti umístění skriptu ve kterém je include umístěno, v případě neúspěchu je hledán stejnojmenný skript v cestě zadané include_path…

    A jako nejjistější variantu bych zapsal tuto, ale to je asi zbytečný detail ;-)

    define(‚DS‘, DIRECTORY_SEPA­RATOR);
    include dirname(__FILE__)­.DS.‚foo‘.DS.‚bar­.php‘;