at – rozšiřujeme syntaxi
Posledním příkladem praktického využití at je rozšíření syntaxe jazyka PHP. Nemohu si pomoci, ale velice se mi líbí sinatra.rb. Jen se podívejte na tu jednoduchost a eleganci (která je převážně zajištěna jazykem Ruby), s jakou lze psát aplikace. S čistým PHP tohoto nikdy nedocílíte. at může pomoci – rozšíříme si jím syntax do nějaké takovéhle podoby:
@get / {
// ... show something ...
return "hello, world!\n";
}
@post / {
// ... create something ...
return "ok, created\n";
}
@put / {
// ... update something ...
return "ok, updated\n";
}
@delete / {
// ... annihilate something ...
return "ok, it's gone\n";
}
Hezké, není-liž pravda? Teď zase jak na to. Prolog:
<?php
require 'at.php';
// zpracování HTTP požadavků
$methods = array(
'GET' => array(),
'POST' => array(),
'PUT' => array(),
'DELETE' => array()
);
1:N
Samozřejmě budeme potřebovat at. Pak si připravíme pole, ve kterém budou callbacky na zpracování jednotlivých HTTP metod. Ty musíme nějak naplnit. Budou k tomu sloužit makra @get ... { ... } apod. Teď k nim ještě nějaký hezký callback. Jelikož má makro vždy název typu HTTP požadavku, můžeme využít toho, že volané funkce dostávají jako poslední argument název makra. Proto si připravíme pouze jednu funkci na přidávání:
$add = function ($regexp, $block, $method /* a.k.a. $name */) use (&$methods) {
$code = '';
foreach ($block as $_) $code .= $_;
$methods[strtoupper($method)]['%' . $regexp . '%'] = create_function('', $code);
};
A naň vlastně uděláme „alias“ několika maker:
$_ = at()
->fn('get', $add)
->fn('post', $add)
->fn('put', $add)
->fn('delete', $add);
Když se vrátíme zpět ke callbacku, je snad jasné, co dělá. První argument se namapuje na první parametr makra (používáme výchozí fnname callback, takže bacha na čárky!), dále dostaneme blok a název makra, což je vlastně název HTTP metody. create_function() vytvoří funkci, která se při zpracovávání HTTP požadavku bude volat. Celé by to šlo také udělat přes notfound, podobně jako konfigurace minule, ale chtěl jsem ukázat využití posledního argumentu callbacku.
Pak si naplníme pole s callbacky spuštěním at:
$_->run(substr(file_get_contents(__FILE__), __COMPILER_HALT_OFFSET__));
Tentokráte to však není všechno, protože požadavek ještě chceme nějak zpracovat:
foreach ($methods[$_SERVER['REQUEST_METHOD']] as $regexp => $code) {
if (preg_match($regexp, $_SERVER['REQUEST_URI'])) {
echo call_user_func($code);
return ;
}
}
Velice jednoduché. Vyzkoušíme, jestli regulární výraz odpovídá požadavku. A pokud ano, tak callback spustíme.
Rozšířená syntaxe
Nakonec ještě zbytek ze souboru (zase je tu totiž ten __halt_compiler()):
__halt_compiler();
@get / {
// ... show something ...
return "hello, world!\n";
}
@post / {
// ... create something ...
return "ok, created\n";
}
@put / {
// ... update something ...
return "ok, updated\n";
}
@delete / {
// ... annihilate something ...
return "ok, it's gone\n";
}
Pokud váš editor nezná __halt_compiler() a nezastaví na něm zvýrazňování syntaxe, máte zvýrazněnou syntaxi v makrech grátis.
Závěr
Není to sinatra.rb, ještě tomu hodně chybí. Ale jak je vidět, rozšířit PHP syntaxi jde :-)
Tímto posledním příkladem končí představování at. Všechny příklady naleznete v repozitáři. Je to open-source, takže jakékoli připomínky, hlášení chyb, používání a jiné věci jsou vítány. Když už nic, tak doufám, že se vám alespoň líbí __halt_compiler() a/nebo closures. Snad se PHP 5.3 stabilizuje brzy a rozšíří se na hostinzích, aby se daly closures využívat. __halt_compiler() je ale přítomný ve všech verzích PHP 5, takže se dá krásně používat již dnes.