phpMinAdmin – kompilace

Školení, která pořádám

Když počet řádek souboru phpMinAdmin.php překročil nějakých 200, začal jsem se v něm zvolna ztrácet. Bylo mi jasné, že i když chci výsledný program udržet v jednom souboru, bude vhodné ho pro účely vývoje rozdělit a jenom pro distribuci zase spojit. Rozdělení bylo celkem jednoduché – zůstal jeden řídící skript, ale jeho komponenty jsem vyčlenil do samostatných souborů:

<?php
if (isset($_GET["table"])) {
    include "./table.inc.php";
}
?>

Kompilace také není složitá – najdou se všechny include a nahradí se obsahem vkládaného souboru:

<?php
function include_file($match) {
    $file = file_get_contents($match[1]);
    $token = end(token_get_all($file));
    return "?>\n$file" . (is_array($token) && ($token[0] == T_CLOSE_TAG || $token[0] == T_INLINE_HTML) ? "<?php" : "");
}
$file = preg_replace_callback('~include "([^"]+)";~', 'include_file', $file);
?>

Takto napsaný kód samozřejmě není univerzálně použitelný, k tomu by musel být mnohem složitější:

Pro účely projektu takto komplexní řešení nebylo potřeba a stačilo použít jednoduchý převod (který oproti popsanému řešení ještě odstraňuje posloupnosti ?><?php a dokáže vytvořit jednojazyčnou verzi).

Binární data

Např. pro zobrazení ikony stahuje phpMinAdmin binární data. Samozřejmě je nevhodné je stahovat z nějakého centrálního úložiště na Internetu – připojení ani nemusí být k dispozici. Nejprve jsem zvažoval použití protokolu data, ten však nepodporuje Internet Explorer. Vyřešila to jednoduchá záměna v generovaném souboru:

<?php
$file = str_replace("favicon.ico", '<?php echo preg_replace("~\\\\?.*~", "", $_SERVER["REQUEST_URI"]) . "?favicon="; ?>', $file);
$file = str_replace("\nsession_start();", '
if (isset($_GET["favicon"])) {
    header("Content-Type: image/x-icon");
    echo base64_decode("' . base64_encode(file_get_contents("favicon.ico")) . '");
    exit;
}
session_start();', $file);
?>
Jakub Vrána, Adminer, 27.7.2007, diskuse: 29 (nové: 0)

Diskuse

Myttys:

"Když počet řádek souboru phpminadmin.php překročil nějakých 200" - hehe, musím se smát. Jsi nejpíš programátor začátečník, běžně píšu programy kde zdroje mají přes 2 MB a stále se v nich naprosto perfektně orientuji. Zkrátka někdo je profík (já) a někdo lama (ty), Howgh.

ikona Jakub Vrána OpenID:

Beru to jako pokus o žert. phpMinAdmin má nyní 2572 řádek. Jejich rozdělení do více souborů není projev lamovství, ale smyslu pro pořádek. Naopak jejich udržování v jednom souboru by nebylo znakem profesionality, ale bordelářství (i když i v bordelu se dá vyznat).

Já se dobře orientuji i v 30MB projektech, ale musejí mít jasnou strukturu.

Pavel:

takovým "profíkům" nemá cenu odpovídat. Jsou tak skvělí, jedineční a neomylní. :)

SendiMyrkr:

Hehe... tady něco smrdí.... hele když si takovej profík co místo těch zcestnejch keců vymyslet něco svýho? nehledě na to že tvůj styl projevu odpovídá inteligenci 16ti letýho frajírka kterej zjistil že php existuje.... :)
ostatním se omlouvám ale tyhle týpky absolutně nesnáším...

ikona finc:

Docela jsi me rozesmal :)
Programovani neni o tom napsat miliony radek kodu, ale napsat co nejmene kodu, ktery je navic kvalitni. Kdyz si dnes vzpomenu na programky, ktere obsahovali par KB a co vsechno umeli, musim dat za pravdu, tem, kteri rikaji, ze skutecni programatori uz nejsou :)

Jinak k te orientaci. Ty Jakube vse pises proceduralne, ze? Mozna to je ten duvod, ze s orientaci je to pak problem.
Osobne jsem se naucil delat veci tak, ze kdyz premyslim nad nejakym navrhem, nadelam si metody, ty necham vratit nejakou defaultni hodnotu, do nich nadefinuji "TODO" (coz mi je schopno IDE dohledat) a pak pracuji na vecech, ktere jsou pro danou cast nejdulezitejsi. Pri zpetnem refactoringu samozrejme prepisi "TODO" na spravny "KOD". Metodik samozrejme existuje spousta, ale toto samotne reseni ma tu ohromnou vyhodu, ze se nemusim zasekavat na vecech, ktere jsou pro mne v tu chvili nepodstatne a mohu se plne soustredit na dany problem.
Jo mit tak dvojnasobnou inteligenci, schopnost zen (premyslet o vice vecech najednou), asi to delam z oleje ;)

ikona Jakub Vrána OpenID:

Já používám objekty tam, kde to má smysl. Konkrétně phpMinAdmin je používá na abstrahování přístupu k databázi. Svým způsobem nepíšu ani procedurálně - píšu prostě kód na globální úrovni a funkce nebo objekty vytvářím tam, kde to něco přinese (obvykle když se stejný kód volá vícekrát). Jinak to je jen samoúčelná vata.

Tvůj způsob psaní kódu se dá použít i u procedurálního a lineárního přístupu. Stejně jako můžeš TODO napsat do metody, tak ho můžeš napsat i do funkce resp. do ifu.

Více malých souborů je přehlednějších proto, že se v nich nemotá kód, který s jejich náplní nesouvisí. A otevření souboru je rychlejší operace než vyhledání textu uvozující nějakou část kódu.

ikona finc:

Souhlas s tim, ze ne vsude jsou objekty zadane. Prikladem muze byt samotny view, kde se jedna o vypis odshora dolu.
Jinak ta vata mi prinasi i to, ze z takovehoto systemu muzu udelat zakladni API, ktere se da pote postavit ruznym spusobem. Pro kontinualni vyvoj je pak jednoduche pridavat nove vlastnosti, kde vesmes pridavam metody, z kterych stavim (neco jako lego).
Nektere metody pak deprekuji, nektere pridavam, neco zrychluji, atd. Ta vata neslouzi jen pro znovupouzitelny kod, ale take pro kod, kteremu rozumi i clovek a pro moznost dlouheho vyvoje.
"Více malých souborů je přehlednějších proto, že se v nich nemotá kód, který s jejich náplní nesouvisí." = Vice malych objektu je ..... :)
Ale je to vec nazoru. Dulezitejsi je vysledek a srozumitelnost pro programatora (at jiz autora ci dalsiho prispevovatele).

Osobne jsem zvedav, zda po pozadavcich zdejsich prispevovatelu, se nedostanes na uroven phpMyAdmina :) Ale i tak, je to skvela prace.

ikona Jakub Vrána OpenID:

Po pravdě řečeno žádný velký požadavek zatím nepřišel (kromě podpory MySQL 4.0, kterou ale dělat nebudu). Většinu menších věcí už jsem přidal a kód nijak významně nenabobtnal. Základní koncept zůstane stejný – jeden soubor, který jen možná časem nebude mít 100 KB, ale třeba 200 KB. Nejvíc přidávají překlady (co překlad, to momentálně 7 KB – to by se dalo zkrouhnout na polovinu použitím číselných identifikátorů nebo jinou organizací polí s překladem, oboje by ale ztížilo práci překladatelům), naštěstí jde už od první verze zkompilovat i jednojazyčná verze.

ikona pa3k:

"otevření souboru je rychlejší operace než vyhledání textu uvozující nějakou část kódu"

To je zaujímavé. Máš to odskúšané? Z fyzikálneho hľadiska by mal byť IMHO pomalší práve presun hlavičiek HDD pri novej požiadavke na iný súbor. Seek podľa hľadaného stringu v rámci jedného súboru - ktorý je navyše pravdepodobne v cache - by mal byť rýchlejší nie? Tipoval by som, že úzke hrdlo serverov dnes nebude v procesorovom čase ale v diskových operáciách.

ikona Jakub Vrána OpenID:

Nemluvil jsem o výpočetním výkonu serveru, ale o čase, který tím stráví člověk při editaci :-). Jinak máš samozřejmě pravdu...

ikona pa3k:

Aha takto, reč je o prehľadnosti. Tak potom áno. Inak phpMinAdmin je zaujímavý počin - pekný minimalizmus. Osobne by som asi prehľadnosť pri požidavke na "všetok kód v jednom súbore" riešil pomocou nástrojov editora ako napr. záložky alebo rôzne pohľady v rámci jedného súboru a takáto vlastná kompilácia projektu by ma asi fakt nenapadla. Každopádne je to pekná ukážka.

kozotoč:

"Programovani neni o tom napsat miliony radek kodu, ale napsat co nejmene kodu, ktery je navic kvalitni."

* v tom se neshodneme: podle mě je ještě víc než délka kódu důležitější, aby se v kódu kdokoli dobře vyznal (s tím souvisí i další kvalita a to znovupoužitelnost)
* "kvalitní kód"... spíš kvalitní návrh, kterému předchází dobrá analýza - prostě: kvalitní "dvakrát měř..."

Sela:

Huh, no jak se obvykle nenecham vyprovokovat k reakci, tak tentokrat musim :) Myttys, prosimte, uz necti toho Hulana, snazis se vyjadrovat jako on, ale absolutne na to nemas a jsi mimo misu. Myslim ze Jakub je jednim z mala profiku na netu, ktery navic jeste svoje napady nesusni a podeli se o ne s ostatnima. Jeho blog  ctu pravidelne a kdyby bylo na netu vic takovych clanku jako pise on, tak by ses mozna o PHP neco dozvedel a mohl bys byt, az ti "sestoupi varlata" skutecny profik ;o) Howgh :o)

ikona finc:

Jsi si jisty, ze to neni ten, jehoz jmeno se nevyslovuje? :D

ikona Jakub Vrána OpenID:

Připojení z adresy končící na 4ginternet.cz, příchod z weblogy.cz a prohlížeč Opera/9.21 to nevylučuje, nicméně tohle myslím není styl Radka Hulána. On je sice arogantní a rád provokuje, ale u mě na blogu se podepisuje svým jménem a vzájemně se myslím docela respektujeme.

roman:

na druhej strane vacsinou prezentuje uz davno vymyslene koleso. hlavny prinos tohto webu vidim v tom, ze je v cestine. negativum je, ze si ludia vytvoria modlu z tohto stylu pisania kodu. a podme teraz vsetci vymyslat svoj cms system a phpmyadmin ;-)

Gaudentius:

Krkem mi lezou kinder developeři - nelez tam, kde se mluví vážně ;-)

Michal:

Perfektní nápad, sice mně ty binární data ve zdrojáku tak trochu bijí do očí, ale celková koncepce je výborná.

Ps: Myttys je dle stylu vyjadřování 14tiletý fracek,který píše svůj první CMS :)

ikona Jakub Vrána OpenID:

Ber to tak, že soubor phpminadmin.php nejsou zdrojáky, ale jen zkompilovaná verze. Mám v plánu ho ještě zkomprimovat, ale funkce php_strip_whitespace() není moc účinná (v mém případě ušetří asi 5 %), takže jsem prozatím upřednostnil to, že i tento soubor si bude chtít někdo prohlížet.

Ondrej Ivanic:

Stale sa da pouzit tokenizator a dvojpismenkove identifikatory  :) Ved co uz len moze byt krajsie ako:

<?php $a1=a2($b3,$c4);$a2=x3($a1,$cd);echo $a2;?>

ikona Jakub Vrána OpenID:

Ano, tokenizátor na to chci použít, ale je potřeba to udělat hodně pečlivě (např. $a - 1 jde zkrátit na $a-1, ale $a - -1 jenom na $a- -1). Krátké identifikátory může vyrobit až kompilátor stejně jako to dělají JS minifiery.

Honza Odvárko:

Při zkracování identifikátorů pozor na proměnné identifikátory $$var

ikona Jakub Vrána OpenID:

Za jakých okolností by se na to mělo dát pozor?

Honza Odvárko:

Pokud dobře chápu:

1) Zkrátit identifikátor znamená např. ve všechny výskyty $ahoj_lidi nahradit za $a, $nazdar_lidi za $b atd.
2) Proměnné identifikátory jsou ovlivněny aktualní hodnotou proměnné určujicí název, takže:

<?php
$ahoj_lidi
= 'Žjůůů';
$nazev = 'ahoj_lidi';
echo($
$nazev); # vypíše obsah proměnné $ahoj_lidi
?>

pokud se zkrátí identifikátory:
<?php
$a
= 'Žjůůů';
$b = 'ahoj_lidi';
echo($
$b); # zkusí vypsat obsah proměnné $ahoj_lidi, ale selže, protože ta je zkrácena na $a
?>

kozotoč:

Druhé takové úskalí je použití $GLOBALS[] (např. uvnitř funkce) a třetí eval(). Jak $$a, tak evalu se dá (u většiny decentně psaných skriptů) vyhnout, použití $GLOBALS uvnitř funkce se dá vyhnout klíčovým slovem global.
U identifikátorů funkcí to je obdobné - problémy po zkrácení jejich názvů by nastaly při použití funkcí pro práci s funkcemi, které např. jejich názvy používají jako řetězec, což není případ Adminera.
Koukám se teď na jeho zdroják a $GLOBALS tam nemá a $$ jen v jednom případě (vypnutí magic_gpc()).

ikona Jakub Vrána OpenID:

Přesně řečeno používám $$ pro vypnutí extenze filter. A používá se přesně v případě, kdy proměnné zkrátit nechci ($_GET a spol.).

ikona dgx:

Účinnější než php_strip_whitespace() by měl být http://www.dgx.cz/trine/item/jak-zredukovat-php-skripty

ikona Jakub Vrána OpenID:

Díky za tip – ten přináší úsporu 13%. Zvážím jeho použití, protože se děsím reportů chyb v podobě „Hlásí mi to chybu na řádku 20“, kdy řádek 20 bude mít 10 KB.

Prdlořeznictví Krkovička, n. p.:

Nejprve poznámečka:
<?php
if (isset($_GET["table"])) {
    include "./table.inc.php";
}
?>
Pro podmíněný blok kódu, který obsahuje jeden příkaz, se složené uvozovky dávat nemusejí, ale pro zpracování a nahrazení include kódem, jsou v tomto případě složené závorky na místě a naopak tam být musejí (stačí si to představit po desubstituci - kdy ve výsledném souboru bude víc příkazů než jen jeden).

..."Ve vkládaném souboru může být použito klíčové slovo return, které způsobí ukončení vkládání"
Jak tedy na to?
Můj nástin řešení:
místo zmiňovaného
<?php
if (isset($_GET["table"])) {
    include "./table.inc.php";
}
?>
použít
<?php
if (isset($_GET["table"]))
    do{
        include "./table.inc.php";
    }while(false);
?>
a vkládaný obsah projíždět přes jednotlivé tokeny, evidovat, počet zanoření, popř. jestli se jedná o funkci/metodu, a při použití return, které není uvnitř funkce, nahradit break(n), kde n je počet zanoření uvnitř vkládaného souboru.

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.