Je tomu právě tři a půl roku, kdy jsem distribuci Texy doplnil o tzv. kompaktní verzi. Zjednodušeně se dá říci, že jde o skript vzniklý spojením všech souborů tvořících knihovnu do jednoho jediného a vynecháním komentářů a nadbytečných mezer. Výsledkem je funkčně identický kód, jen s krapet hustší konzistencí. (Prostě je hustéééj. Jak Salko!)
Záměrem bylo zjednodušit nahrávání knihovny na server – uploadovat desítku malých souborů přes FTP bývá značně pomalejší, než nahrát soubor jeden. Jako vedlejší efekt se ukázalo, že jednosouborová knihovna znatelně zvyšuje výkon aplikace – klidně o 30 %. Používání kompaktních verzí se ujalo a od té doby většina bugreportů hlásila chybu na řádce 1 🙂
S příchodem jmenných prostoru v PHP 5.3 se generování kompaktních
verzí poněkud zkomplikovalo – zatím totiž platí, že jeden soubor
může obsahovat jen jeden jmenný prostor už to neplatí. To znamená,
že „jednosouborová“ verze bude mít přinejmenším tolik souborů, kolik
je v knihovně jmenných prostorů, plus případné další soubory řešící
problémy se vzájemnou závislostí mezi prostory.
Zároveň však PHP 5.3 přichází s novinkou, která si klade za cíl vnést do kompaktních verzí nový svěží vítr: PHAR – PHP archive. Ostatně myslím, že promluvím za nás všechny, když řeknu: nemusí pršet, hlavně když kape!
Jak takový PHAR balíček vytvořit? Nejprve je nutné v PHP.INI zapnout
extension=php_phar.dll
a nastavit direktivu
phar.readonly = Off
. Následující kód zkonvertuje celý Nette Framework do
souboru nette.phar
$phar = new Phar('nette.phar');
$phar->buildFromDirectory('libs/Nette'); // enter here path to Nette
$phar->setStub("<?php
Phar::mapPhar('nette.phar');
require 'phar://nette.phar/loader.php';
__HALT_COMPILER();");
$phar->compressFiles(Phar::GZ); // or Phar::BZ2
Nejprve se vytvoří nekomprimovaný archiv ze všech souborů v určeném
adresáři a jeho podadresářích – jde o obdobu TAR archivu. Následně se
definuje tzv. stub neboli zaváděcí program. Jeho úkolem bude načíst soubor
loader.php
, který je součástí Nette Frameworku a nalézá se
vlastně uvnitř PHAR archivu. Stub musí být ukončen zvoláním
__HALT_COMPILER()
. Poté je možno archiv zkomprimovat.
Příklad použití:
require 'nette.phar';
echo Html::el('strong')->setText('It works!');
Vypadá to báječně, že? Ovšem podívejme se na věc podrobněji. PHP
skripty nejsou v archivu nijak minimalizované, nejsou z nich odstraněny
zbytečné komentáře ani mezery. To je potřeba udělat ručně. Takže
zatímco komprimovaný nette.phar
má nějakých 180 kB, stejný
archiv vygenerovaný z kompaktní verze Nette (tj. místo adresáře
libs/Nette
použijeme libs/Nette.compact
) váží
pouhých 50 kB. Nicméně pokud si uvědomíme, že
- minimalizace kódu vede k rychlejšímu parsování (závislost bude dost možná lineární)
- dekomprimace naopak nutně zpomaluje
dojdeme k závěru, že ideální bude generovat PHAR rovnou z kompaktní verze a ukládat jej nekomprimovaný. Nojo – ale proč teda rovnou nezůstat u kompaktní verze? Bez PHAR režie navíc?
Důvod existuje. Kompaktní verze se vždy načte celá, zatímco PHAR lze parsovat a kompilovat po částech. Takže Zend Framework bude vhodnější zabalit do PHARu, u dibi nebo Texy si můžeme dovolit plný výkon kompaktní verze.
Komentáře
Martin Malý #1
Nejpozději s uvedeném téhle novinky přijde kdosi s nápadem zPHARovat front controller i všechny další controllery a vytvořit vlastně jeden takový mohutný index.php, který bude obsahovat logiku pro celou aplikaci… bože… takovou novinku unesou programátoři maximálně třikrát za deset let!
David Grudl #2
#1 Martine Malý, Myslíš tohle?
kukulich #3
„…zatím totiž platí, že jeden soubor může obsahovat jen jeden jmenný prostor…“
To není pravda, i v současné verzi jmenných prostorů bez složených závorek může být v jednom souboru více jmenných prostorů. Původně to opravdu bylo tak, jak je v článku uvedeno, ale kvůli různým frameworkům (myslím, že zmiňovali především Symfony) bylo povoleno více jmenných prostorů v jednom souboru. Ale právě proto se začalo znovu uvažovat o syntaxi se složenými závorkami.
pmg #4
Mělo by smysl jednotlivé soubory před archivací předkompilovat?
David Grudl #5
#3 kukulichu, máš pravdu, v poslední verzi to skutečně jde. Ačkoliv stále nemůže být v jednom souboru kód bez jmenných prostorů a kód s nimi.
OndroNR #6
a co autoload? moc sa v tom nevyznam
A. #7
Vypadá to zajímavě, už se těším, až si do PHARu zabalím ZF. Díky 🙂
Jan Tvrdík #8
Jaká by byla rychlost např. Texy!, kdyby se „zkomprimovali“ jednotlivé soubory zvlášť a nebalily se všechny dohromady? Pokud jsou totiž sbaleny v jednom souboru, tak je tam obsažen i kód, který se nemusí využít. Pokud by byly zabaleny samostatně, tak by se nepotřebné moduly (předpokládám) vůbec nenačetly.
David Grudl #9
#8 Jane Tvrdíku, V případě Texy se právě použíjí téměř všechny soubory. U dibi se sice obvykle použije jen jeden z ovladačů, nicméně i tak mi vychází rychlejší načíst vše v minimalizované formě.
Ondrej Ivanic #10
Používání kompaktních verzí se ujalo a od té doby většina bugreportů hlásila chybu na řádce 1
Tak toto musi byt peklo :)
Je jednosuborove Texy rychlejsie ako viac suborove Texy + op. cache (napr. APC)? Ak to tak nie je potom sa mi to zda ako zbytocna komplikacia urobit jeden subor (jednosuborove + op cache bude asi najrychlejsie, ale …)
v6ak #11
Bude fajn, až bude PhpMinAdmin distribuován jako index.phar 😁
pmg #12
#8 Jane Tvrdíku, PHP načte jen hlavičku archivu se seznamem souborů a vlastní kód čte, až když je potřeba. Důležité je, že má po celou dobu otevřený jen jeden soubor, ve kterém se přesouvá. Taková je má představa.
Přesná struktura archivu se dá vyčíst ze zdrojů PEAR pakáže PHP Archive. Letmo jsem na to kouknul a myslím, že je nejlepší jednotlivé soubory před archivací prohnat ještě PHP bytecode Compilerem.
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.