Díky chytře vymyšlenému kódování UTF-8 ji lze spolehlivě používat
i pro takto kódované řetězce. Navíc jako první dva argumenty lze uvést
pole a funkce potom provede vícenásobné nahrazení. A tady narážíme na
první špíček, který je třeba mít na zřeteli. Každé nahrazení
prochází řetězec znovu, pokud bychom tedy chtěli ve větě
pánské dárky prohodit dá <⇒ pá
a získat tak dánské párky (švédská delikatesa!), žádné
pořadí argumentů k cíli nepovede:
Pokud bychom hledali výskyty podle složitějších pravidel, využijeme
regulární výrazy a funkci preg_replace. Ta také umožňuje
vícenásobné nahrazování a chová se stejně jako str_replace.
Teď však mířím jinam. Potřebuji v řetězci nahradit všechny čísla
slovem hafo, což je snadné:
$s = "Radek tvrdí, že má IQ 151. Pěkný sběratelský kousek!";
echo preg_replace('#\d+#', 'hafo', $s);
Zobecněme kód, nechť umí čísla nahradit čímkoliv, co mu předáme
v proměnné $replacement. Řada programátorů použije:
Což bohužel není dobře. Je třeba si uvědomit, že i v nahrazovaném
řetězci mají určité znaky speciální význam (konkrétně lomítko a
dolar), proto ho musíme escapovat. Správné obecné
řešení je:
return preg_replace('#\d+#', addcslashes($replacement, '$\\'), $s); // ok
Pár dobře míněných tipů, jak navrhnout strukturu
jmenných prostorů (namespaces) a názvů tříd.
Jmenné prostory jsou asi nejznámější novinkou PHP verze 5.3. Jejich
hlavním smyslem je zabránit jmenným konfliktům a umožnit zkracovat
(aliasovat) názvy tříd pro používání v jednom souboru. V praxi se
ukazuje, že konfliktům lze předejít i použitím 1–2 písmenného
prefixu, stejně tak jsem se nikdy nedopustil názvů tříd jako
Zend_Service_DeveloperGarden_Response_ConferenceCall_AddConferenceTemplateParticipantResponseType
(97 znaků, zajímalo by mě, jak s tím dodržují své pravidlo o max.
délce řádků 80 znaků 🙂 ). Avšak PHP kráčí ve šlépějích Javy a
tak tu máme namespaces. Jak s nimi naložit?
Přínos jmenných prostorů
Asi nejsložitější otázka, na kterou si musíte odpovědět, zní: čemu
prospěje přejmenovat třídu:
sfForm → Symfony\Component\Form\Form
Otázka je osvědčeným závdavkem k nekonečným flame wars. Z hlediska
pohodlí programátora, intuitivnosti a zapamatovatelnosti je vhodnější
původní stručné a výstižné sfForm. Odpovídá totiž tomu,
jak třídu programátoři označí hovorově, tj. „formulář v Symfony“.
Nový a delší název je zase správný z jiných hledisek, u nichž si
ovšem nejsem jist, jestli je běžný uživatel ocení.
Jak jmenné prostory
rozvrhnout?
Syntaktickou stránku použití popisuje
dokumentace, objevit správné vzory však chce praxi, na kterou zatím
nebylo dost času. Prostory v PHP mají svá specifika daná celou řadu
faktorů, proto není ideální 100% kopírovat konvence používané třeba
v Javě nebo .NET. Dá se z nich však dobře vycházet.
Více si řekneme u jednotlivých pravidel pro pojmenování.
1) třída má mít
výstižný název i bez uvedení NS
Název každé třídy i bez jmenného prostoru musí vystihovat její
podstatu. Nevhodné by bylo přejmenovat třídu ArrayIterator →
Spl\Iterators\Array, protože pod názvem Array by
člověk neočekával iterátor (pomiňme, že třídu nelze nazvat klíčovým
slovem). A pozor, ani z názvu Spl\Iterators\Array nemusí být
zřejmé, že jde o iterátor, protože nelze sázet na to, že namespace
Spl\Iterators obsahuje pouze iterátory. Mohou tam být třeba
i nějaké pomocné třídy.
Pár příkladů:
nevhodné: Nette\Application\Responses\Download – nelze
dovodit, že Download je odpověď
nevhodné: Zend\Validator\Date – předpokládali byste, že
Date je validátor, nikoliv datum?
nevhodné: Zend\Controller\Request\Http – předpokládali
byste, že Http je požadavek?
Proto krom specializace tříd je vhodné v názvu ponechat i obecnost:
Pochopitelně i samotný název jmenného prostoru musí být výstižný a
výhodou je název kratší, bez zbytečností. Takovou zbytečností se mi zdá
např. Component v Symfony\Component\Routing, protože
bez něj by název nijak neutrpěl.
V některých situacích je třeba se rozhodnout mezi jednotným a množným
číslem (Zend\Validator vs Zend\Validators), což je
podobně nerozhodný problém, jako při volbě jednotných a množných čísel
u databázových tabulek.
3) rozlište jmenné prostory a
třídy
Pojmenovat třídu stejně jako jmenný prostor (tj. mít třídy
Nette\Application a Nette\Application\Request) je
technicky možné, mohlo by to však programátory mást a lépe se bude tomu
vyhnout. Myslete i na to, jak dobře se bude výsledný kód číst nebo jak
budete API někomu vysvětlovat.
Ideální je, pokud název třídy a název prostoru neobsahují duplicitně
stejnou informaci.
místo Nette\Http\HttpRequest raději
Nette\Http\Request
místo
Symfony\Component\Security\Authentication\AuthenticationTrustResolver
raději třídu TrustResolver
Třída Nette\Http\Request neodporuje pravidlu č.
1 o výstižném názvu třídy i bez uvedení jmenného prostoru, naopak
nám dovoluje elegantně využít parciální namespace:
use Nette\Http; // alias pro namespace
// dostupné jsou všechny třídy via Http:
$request = new Http\Request;
$response = new Http\Response;
// a navíc Http\Response je srozumitelnější než samotné Response
Pokud jmenné prostory chápeme jako balíčky, což je obvyklé, vede to
k nešťastnému duplikování posledního slova:
Zend\Form\Form
Symfony\Component\Finder\Finder
Nette\Application\Application
Jmenné prostory také doslova svádí sdružovat třídy (např. různé
implementace téhož rozhraní apod.) do vlastních prostorů, což opět
vytváří duplicity:
Nette\Caching\Storages\FileStorage – tj. všechny
úložiště v samostatném prostoru Storages
Zend\Form\Exception\BadMethodCallException – všechny
výjimky do Exception
Symfony\Component\Validator\Exception\BadMethodCallException –
opět všechny výjimky do Exception
Sdružující namespaces prodlužují název a vytváří v něm duplicity,
protože obecnost často není možné z názvu tříd odstranit
(1. pravidlo). Jejich výhodou může být lepší orientace ve vygenerované
API dokumentaci (téhož by však šlo dosáhnout i jinak) a snazší
dostupnost při použití plnohodnotných IDE s napovídáním. Každopádně
je doporučuji používat jen s rozvahou. Například pro vyčlenění výjimek
se moc nehodí.
5) nezaměnitelnost tříd
z více prostorů
Dle bodu 1) má mít třída výstižný název, což ale neznamená, že má
být i jednoznačný v rámci celé aplikace. Obvykle stačí, aby byl
jednoznačný v rámci jmenného prostoru. Pokud se však v kódu často
používají vedle sebe dvě třídy z různých prostorů, nebo pokud mají
mezi sebou jinou podstatnou souvislost, neměly by mít stejný název. Jinými
slovy, nemělo by být nutné používat AS v klauzuli USE.
6) jednosměrné závislosti
Zvažte, jaké závislosti mají mezi sebou mít třídy z jednotlivých
jmenných prostorů. Snažím se dodržovat:
pokud má třída ze jmenného prostoru A\B závislost na třídě ze
jmenného prostoru A\C, neměla by žádná třída z A\C mít závislost
na A\B
třídy ze jmenného prostoru A\B by neměly mít závislost na třídě
z prostoru A\B\C (tohle berte s rezervou)
p.s.: neberte prosím tento článek jako dogma, jde jen o zachycení
aktuálních myšlenek
Když jsem se dozvěděl, že Jakub Vrána
píše knížku 1001 tipů a triků o PHP, samozřejmě mě napadlo
pár trapných fórků („1001 vtipů o PHP“, „to jich bude devět?“
nebo „č. 1: znáte Ruby?“) ale pak jsem si uvědomil, jak je to vlastně
šíleně velké číslo. Schválně, zkuste vymyslet a napsat padesátku. Dáte
to? Já leda s odřenýma játrama. No a pak další. A další. A další!
Uff. Když pak Jakub hlásil, že se blíží do třetiny, vzpomněl jsem si na
Marvinovo „Nejhorší bylo těch prvních deset miliónů.“
Humor mi došel ve chvíli, kdy mě Jakub požádal, jestli bych mu udělal
korekturu. Co si budeme povídat, když váš kamarád napíše knihu, tak ji od
něj dostanete, někam ji důmyslně založíte a až se setkáte, tak mu
řeknete, že jste ji samozřejmě četli a jako že to fakt bylo dobrý a
poplácáte ho po rameni nebo tam někde. Alespoň tak velí bonton. Ovšem
když máte dělat korekturu, ocitáte se vstříc hrozbě, že ji doopravdy
budete muset přečíst! Že bych mu ji po týdnu vrátil netknutou a bez
jediného škrtu („čéče, sem to fakt čet a žádnou vyloženě jako chybu
sem tam nenašel…“), o tom jsem vůbec neuvažoval, by mi to nezbaštil.
Pustil jsem se do čtení a zjistil, že to je hodně dobrý materiál.
Byť školy nemám a z odborné literatury jsem přečetl jen Pixyho, Kruga
a Koska, cítím se v PHP poměrně zdatný. Co mi může kniha od Jakuba dát?
Ejhle, může. Jakub totiž na vydavatele ušil pěknou kulišárnu, ta kniha je
o PHP spíš mimochodem. Je to prostě hromada zajímavých tipů a nápadů
pro všechny, kdo se zabývají webovými aplikacemi. Navíc originálních
tipů, nejde totiž o tištěnou verzi Jakubova blogu. V žádném případě
nečekejte referenční příručku PHP nebo nudnou přehlídku funkcí, kdepak.
Najdete tu tipy počínaje návodem, jak skrýt emailovou adresu před roboty,
přes generování sitemap až po pádné argumenty, zda mít doménu s
www. nebo bez.
U toho bych se zastavil. Ač s Jakubem máme na mnohé věci odlišné
názory, s ním je radost nesouhlasit. On má totiž svůj postoj vždycky
podpořený jasnou argumentací. U něj neexistuje „to se dělá tak,
protože to tak dělá každý“ nebo „protože tak to dělá
Nielsen|Zeldman|Lerdorf|Torvalds|(doplň si svou kapacitu)“, ale protože nad
tím přemýšlel a došel k nějakému závěru. A to se jako červená niť
táhne celou knihou. Takže ačkoliv bych mohl s něčím nesouhlasit, stěží
bych v ní hledal chybu. Takovou preciznost jsem zažil snad jen u knih
Douglase Crockforda.
Ale ať jen nechválím – kniha je sbírkou nápadů, které jsou sice
tematicky uspořádané, ale chybí mi tam průvodní slovo, co by z toho
dělalo souvislé čtivo. Chybí mi tam Miloš Frýba. A na můj vkus obsahuje
příliš málo humoru a nadsázky 🙂
Každopádně knihu vřele doporučuji každému PHPčkaři, své si v ní
najdou jak začátečníci, tak matadoři. Za cenu jednoho bifteku není nad
čím váhat. A neříkám to proto, že je v ní zmíněné Nette 🙂
V knihkupectvích by měla být od pondělí, nicméně dokud Jakub
nabízí možnost nechat si ji za stejnou cenu poslat s jeho podpisem, tak
knihkupectví nemají šanci.
Dlouhá léta mi ze zdrojáků generoval API dokumentace phpDocumentor. Vývoj tohoto nástroje ustrnul
a PHP 5.3 je mu cizí, zejména chybí podpora jmenných prostorů. Začal jsem
hledat alternativu. Bohužel žádná sláva.
On ani samotný phpDocumentor nebyl žádný zázrak. Dodáván se sadou
šablon, jednahnusnější
než druhá,
vedle toho i taková Lupa.cz vypadá jako fešanda. Chápu, „programátoři
sobě“, oželel bych nějaké eye-candy, ale šablony jsou tak zoufale nepřehledné
a odpudivé, že si neumím představit takovou dokumentaci používat
dobrovolně. Užitná hodnota nulová. A nabídka alternativních
šablon není.
Vyzkoušel jsem phpDoctor, doxygen a PHP_UML, u kterého jsem
nakonec zůstal. Jeho standardně vygenerovaná dokumentace asi nejvíc
odpovídala tomu, co jsem hledal (ukázka). Jenže
aplikace je taková PEARovská, hned v úvodu člověka přivítá
Notice: Undefined variable: errorLevel, musel jsem se hrabat ve
zdrojácích a opravit několik bugů, strávil moře času úpravou XSL
šablon. Ještě štěstí, že PHP_UML generuje dokumentaci neskutečně
rychleji než phpDocumentor, takže jsem viděl výsledek každého zásahu
takřka ihned a ne až po dlouhých minutách. Stále tomu ale chyběly dost
podstatné věci, a tehdy mě napadlo…
Pokusím se vysvětlit postup, jak jsem Apigen psal. Dopředu prozradím, že
se vešel do pouhých 150 řádků (!) kódu + šablony.
Jak na to
Nejprve: zdrojový kód lze analyzovat buď vlastním parserem, nebo využít
reflection. Jedním
z hlavních požadavků bylo, že generátor bude umět plnohodnotně pracovat
s interními třídami PHP (třeba takto). Což mi
jinde citelně chybělo. Jelikož interní třídy žádný zdrojový kód
nemají, zvolil jsem reflexi. To znamená, že všechny třídy, pro které chci
generovat dokumentaci, musím načíst. Projít adresářovou strukturu třeba
Finderem a postupně volat
require pro každý soubor nejde – mezi třídami jsou
závislosti a je nutné je načítat v pořadí: rozhraní, rodiče, potomci.
Nelehký úkol, ale vyřešil jej RobotLoader:
$robot = new Nette\Loaders\RobotLoader;
$robot->addDirectory($dir); // adresář, který chceme dokumentovat
$robot->register(); // zapne autoloading
// getIndexedClasses vrací seznam nalezených tříd a souborů
foreach ($robot->getIndexedClasses() as $file) {
require_once $file;
}
$robot->unregister();
Když nyní načtu třídu, která má vazbu na dosud nenačtenou třídu
nebo rozhraní, přijde ke slovu RobotLoader a situaci vyřeší. Takže to
bychom měli. Paráda.
Když operuješ sám sebe
Avšak objevil se tu oříšek. Jak generovat API dokumentaci pro knihovnu,
kterou pro generování API dokumentace používám? Slepice a vejce hadr.
Řešení vidím dvě: buď použít jako vstup přímo tu kopii Nette, kterou
používá generátor, nebo vytvořit alternativní vesmír, kde se Nette
nejmenuje Nette. Druhý způsob se mi zdá rozumnější, nakonec ho používám
pro generování distribučních balíčků Nette. Jde o to, že generátor
používá knihovnu NetteX, která se liší jen v tom, že sídlí v
„oiksovaném“ jmenném prostoru.
Ano, anotace
Aby byl model plnohodnotný, potřeboval jsem přihlížet k anotacím.
Například vynechat všechny elementy s anotací @internal,
určovat vrácené hodnoty metod dle anotace @return atd. Tady jsem
opět využil skutečnosti, že Nette Framework podporuje anotace a pro
reflektování použil Nette\Reflection.
$class = new Nette\Reflection\ClassReflection($name);
if ($class->hasAnnotation('internal')) {
...
}
Třídy z Nette\Reflection podporují tzv. properties,
tudíž se příjemněji používají v šablonách, kde místo
$tmp = $method->getAnnotations();
foreach ($tmp['params'] as $value) ...
mohu psát stručnější
foreach ($method->annotations['params'] as $value) ...
Nakonec jsem pro reflexi tříd použil vlastního potomka
Nette\Reflection\ClassReflection s přidanou funkcionalitou.
Přičemž Nette automaticky zajišťuje, aby metody jako
getDeclaredClass() opět vracely instanci mé třídy.
Svěží 🙂
Ša-la-la-blo-ny
Při generování HTML souborů jsem naplno využil sílu šablonovacího
jazyka Latte. Ten lze používat nejen ve spojitosti s MVC aplikacemi, ale
naprosto kdekoliv. Využil jsem
oddělený layout, dědičnost bloků i tzv. n:attributy.
Výsledkem jsou skutečně dobře čitelné šablony. Příklad:
{* $implementers je pole objektů ClassReflection *}
<div n:if="$implementers">
<h4>Direct Known Implementers</h4>
{foreach $implementers as $item}
<a href="{$item|classLink}">{$item->name}</a>{sep}, {/sep}
{/foreach}
</div>
Uvedený <div> se vykreslí pouze v případě, že pole
$implementers je neprázdné. Jednotlivé položky vykreslí jako
odkazy oddělené čárkou. A makro {sep}...{/sep} zajistí, aby
se čárka (tj. separátor) neobjevila za poslední položkou. Živé to
můžete vidět třeba tady.
Jiným příkladem je šablona, která vygeneruje v JavaScriptu seznam
všech tříd pro potřeby našeptávače (výsledek):
// $classes je opět pole objektů ClassReflection
{contentType javascript}
var classes = {$classes|values|map:'return $value->name;'};
Pro generování obarvených zdrojových kódů jsem použil skvělou
knihovnu FSHL, kde stačilo doplnit
seznam klíčových slov PHP 5.3. Obsah doc-bloků jsem zkusil formátovat
pomocí Texy ve spojení s FSHL a výsledek se
mi zdá dostačující.
Světlo světla spatřil Apigen
Naprogramovat celý generátor trvalo pár hodin, což je řádově méně,
než bych strávil úpravou existujících knihoven. Výsledkem totiž bylo, jak
jsem zmínil, pouhých 150 řádků kódu. Ač jsem ho nijak rychlostně
neoptimalizoval, dokumentaci k Nette vygeneruje za cca 11s, zatímco
phpDocumentor se s tím trápí přes dvě minuty. Ani jsem nečekal, že se
Nette Framework tak výborně hodí na tak netypický úkol.
Mnohem víc času jsem pak strávil vylaďováním šablon, připojil jsem
jQuery a hrál si s tříděním metod a dalšíma opičkama. Generátor jsem
opatřil rozhraním pro ovládání z příkazové řádky, přidal další
fíčůrky a dopsal komentáře, takže v tuto chvíli je těch řádků
určitě alespoň jednou tolik 🙂
Tedy alespoň by neměli. PHP je jazyk s poměrně laxním přístupem
k chybám a tudíž vyžaduje od programátora vyvinout větší úsilí při
jejich ošetřování. Nenechte si namluvit opak. Článek je reakcí na dobře míněnou radu
Jakuba Vrány.
Existují dva tradiční způsoby, jak chyby oznamovat:
vyhozením výjimky
návratovou hodnotou
Takřka všechny knihovny dodávané s PHP používají druhý způsob,
protože výjimky byly do jazyka zavedeny až v páté verzi. Což je v mnoha
případech na škodu. Programátor totiž musí neustále otrocky kontrolovat
návratové hodnoty a ošetřovat chybové stavy. A zároveň je tu riziko, že
na to zapomene. Přesněji řečeno, ani ne tak „zapomene“, jako spíš se
na to „vy…kašle“, protože to ve světě PHP platí za normu. Nakonec,
podívejte se třeba do dokumentace fread a spočítejte,
kolikrát v příkladech ošetřili návratovou hodnotu jakékoliv funkce.
Při takovém stylu práce pak není divu, že programátoři považují
výjimky za něco otravného, co se (cituju Jakuba) „nedá
ignorovat“, zatímco „chyby indikované návratovou hodnotou
ignorovat lze a program nejspíš nějak pracovat bude.“ Notykrávo.
Co přesně znamená ono nějak pracovat? Třeba:
// přesouváme z disku na disk
copy('c:/oldfile', 'd:/newfile');
unlink('c:/oldfile');
// pokud první operace selže, soubor se nenávratně smaže
$link = new mysqli('localhost', $user, $pass, 'eshop');
...
$link->query('USE testdata'); // přepneme se z ostré do testovací databáze
$link->query('DELETE FROM orders');
// pokud předchozí operace selže, vymažou se objednávky z ostré databáze
// BTW věřili byste, že výchozí nastavení query() při chybě nevyhodí ani noticku?
// smažeme soubor z adresáře 'test'
ftp_chdir($connection, 'test');
ftp_delete($connection, 'database.sdb');
// pokud předchozí operace selže, vymaže se kupříkladu ostrá databáze
A pak jsou případy, kdy nějak pracovat znamená zařvat
s neošetřitelnou fatální chybou:
// načtení konfigurace
$defaults = array('host' => 'localhost', 'charset' => 'utf8');
$config = parse_ini_file('config.ini');
$config = $config + $defaults;
// pokud předchozí operace selže a vrátí false, skončí sčítání fatální chybou
function saveConfig(array $config) { ... }
$config = parse_ini_file('config.ini');
saveConfig($config);
// pokud předchozí operace selže a vrátí false, skončí opět fatální chybou
mysqli_connect('localhost', $user, $pass)
->query("SET NAMES 'utf8'");
// pokud první operace selže, skončí opět fatální chybou
V PHP jsou k dispozici tři knihovny pro regulární výrazy: PCRE, Oniguruma a POSIX Regex. Druhá
jmenovaná nemusí být vždy k dispozici a třetí je zavržená, proto byste
měli používat výhradně šikovnější a rychlejší knihovnu PCRE. Bohužel
implementace trpí docela nepříjemnými nedostatky, a to ve všech
verzích PHP.
Činnost jednotlivých funkcí preg_* lze rozdělit do
dvou kroků:
kompilace regulárního výrazu
exekuce (hledání, záměna, filtrování, …)
Sympatické je, že PHP zkompilovanou podobu regulárních výrazů udržuje
v cache a tudíž se kompilují vždy jen jednou. Proto je vhodné používat
statické regulární výrazy, tj. negenerovat je parametricky.
Teď k těm nepříjemným záležitostem. Pokud se během kompilace odhalí
chyba, PHP na ni upozorní chybou úrovně E_WARNING, avšak
návratová hodnota funkce je nejednotná:
preg_filter, preg_replace_callback,
preg_replace vrací null
preg_grep, preg_match_all,
preg_match, preg_split vrací false
Dobré je vědět, že funkce vracející skrze referenci pole
$matches (tj. preg_match_all a
preg_match) při kompilační chybě argument nevynulují, tudíž
testovat návratovou hodnotu má opodstatnění.
PHP od verze 5.2.0 disponuje funkcí preg_last_error vracející kód
poslední chyby. Avšak pozor, týká se to pouze chyb vzniklých během
exekuce! Pokud dojde k chybě během kompilace, hodnota
preg_last_error se nevynuluje a vrací předchozí hodnotu. Pokud
tedy návratová hodnota preg_* funkce není null
resp. false (viz výše), rozhodně nepřihlížejte
k tomu, co preg_last_error vrací.
K jakým chybám může dojít během exekuce? Nejčastějším případem
je překročení pcre.backtrack_limit nebo nevalidní UTF-8 vstup
při použití modifikátoru u. (Poznámka: neplatné
UTF-8 v samotném regulárním výrazu se odhalí již při kompilaci.)
Nicméně způsob, jak PHP s takovou chybou naloží, je naprosto
neadekvátní:
nevygeneruje žádnou zprávu (silent error)
návratová hodnota funkce může naznačovat, že je vše v pořádku
chybu lze zjistit až následným zavoláním
preg_last_error
Zastavím se u té návratové hodnoty, což je asi největší zrada.
Proces se totiž vykonává do chvíle, než se chyba objeví a poté se vrátí
částečně zpracovaný výsledek. A to v naprosté tichosti. Jenže ani
tohle neplatí vždy, třeba trojice funkcí preg_filter,
preg_replace_callback, preg_replace umí i při
exekutivních chybách vracet null.
Zda došlo během exekuce k chybě lze zjistit jedině voláním
preg_last_error. Ale jak už víte, tato funkce vrací nesmyslný
výsledek v případě, že došlo naopak k chybě kompilace, musíme tedy
obě situace rozlišit přihlédnutím k návratové hodnotě funkce, zda-li je
null resp. false. A jelikož funkce vracející
null při chybě kompilace umí vracet null i při
chybě exekuce, lze konstatovat asi jen tolik, že PHP je nadevší pochybnost
zkurvený jazyk.
Jak by vypadalo bezpečné použití PCRE funkcí? Například takto:
function safeReplaceCallback($pattern, $callback, $subject)
{
// callback musíme ověřit sami
if (!is_callable($callback)) {
throw new Exception('Neplatny callback.');
}
// testujeme výraz nad prázdným řetězcem
if (preg_match($pattern, '') === false) { // chyba kompilace?
$error = error_get_last();
throw new Exception($error['message']);
}
// zavoláme PCRE
$result = preg_replace_callback($pattern, $callback, $subject);
// chyba exekuce?
if ($result === null && preg_last_error()) {
throw new Exception('Chyba zpracovani regularniho vyrazu.', preg_last_error());
}
return $result;
}
Uvedený kód transformuje chyby do výjimek, nesnaží se však potlačit
výpis varování.
Bezpečné zpracování regulárních výrazů je implementováno ve
třídě Nette\Utils\Strings.
Drazí provozovatelé hostingů, už je to tady. Před bezmála půl rokem
vyšlo PHP 5.3.0. Přirozený nástupce řady 5.2 bez zpětně
nekompatibilních změn. Víme, že jste s nasazením čekali, než se objeví
následující setinková verze. Dnes se tak stalo, PHP 5.3.1 je venku.
Trojková řada přináší velké
množství vylepšení, na které my, krásní a bohatí programátoři,
toužebně čekáme. Neotálejte proto více a novou verzi PHP nám dopřejte.
Když budete chtít, stihnete ji nasadit ještě dnes v noci! Stejně
v televizi nedávají nic zajímavého. Děkujeme!
(tipy na hostingy, které už novou verzi mají, můžete posílat do
komentářů)
Pokud máte dojem, že ty 140 znakové kravinky, co píšete na Twitter, je
nutné zálohovat pro příští generace, ať už z důvodu, že Twitter má
občas výpadky doprovázené ztrátou dat, nebo vám někdo může účet
ukrást a smazat, nebo se blížíte k limitu 3200 štěbetnutí, po kterém
se (prý) nejstarší kusy odmazávají, nebo prostě chcete mít vše na disku
kvůli lepšímu vyhledávání, je tento článek pro vás.
Protože jsme na blogu o PHP, nebudu zde popisovat online služby určené
k zálohování, ale rovnou vypustím z klávesnice kus kvalitního
objektového kódu ;)
Nejprve si stáhněte knihovničku Twitter for
PHP (verzi 2.0) od stejnojmenného autora s autorem blogu. A pak si
vytvořte zálohovač twitter-backup.php:
<?php
set_time_limit(0);
require 'twitter.class.php';
// zde dejte své přihlašovací údaje
$twitter = new Twitter($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret);
// naráz lze načíst maximálně 200 twittů, tož budeme stránkovat
$page = 1;
$retry = 0;
do {
try {
$channel = $twitter->load(Twitter::ME, 200, $page);
if (empty($channel->status)) { // prázdný výstup? narazili jsme na konec
break;
}
file_put_contents("twitter-backup.$page.xml", $channel->asXml());
echo "Ulozena stranka c. $page\n";
$page++;
$retry = 0;
sleep(1);
} catch (TwitterException $e) {
echo "Error: {$e->getMessage()}\n";
if ($retry > 3) break; // chyby s občas stávají, dáme 3 pokusy
$retry++;
}
} while (true);
Po spuštění se vytvoří soubory twitter-backup.1.xml,
twitter-backup.2.xml atd., podle toho, jak jste aktivní
štěbetal. XML obsahuje skutečně vše, včetně informací, na koho zpráva
reaguje, z jakého zařízení byla poslána nebo jaké máte barvičky
v profilu.
Prapůvodně měl být na tomto místě ohlas na školení Jakuba Vrány Konfigurace
a výkonnost MySQL. Chtěl jsem psát o tom, že ačkoliv mě Jakub
dopředu varoval, že téma konfigurace MySQL není gór moc kůl, obavy se
ukázaly jako liché, neboť prakticky každou vlastnost demonstroval na
živých příkladech a tím držel posluchače ve střehu. Jako skvělý
prezentační nástroj se přitom ukázal Adminer. Až jsem měl pocit, že si ho
vyrobil speciálně k tomu účelu, protože s phpMyAdminem by tak ladně
demonstrovat některé rysy MySQL nešlo. No a pak tu mám několik drobností,
které bych školení vytkl, nicméně…
…Nicméně hlubší rozbor tohoto konkrétního školení vynechám. Jednak
proto, že ho Jakub aktuálně nenabízí. (Přesněji řečeno nabízí řadu jiných školení a máte poslední
šanci se na ně přihlásit, první z nich je totiž už zítra). A také
proto, že více čtenářů bude zajímat odpověď na úvodní otázku.
Začnu obecně: aby pro vás školení mělo přínos, musí dojít
k určité konjunkci hvězd:
přednášející musí tématu výborně rozumět
přednášející musí umět školit
přednášející musí mít školení dobře připravené
a vy si musíte vybrat správný kurz (a ptát se)
Že neříkám nic objevného? Kéž by. Divili byste se, kolik firem
posílá lidi na školení k pánům nikdy-jste-o-mně-neslyšeli,
jsem-o-kapitolu-před-vámi nebo říkají-mi-uspavač-hadů.
Není lepší jít na doopravdické školení? Obzvlášť pikantní je, když
se na takovém doopravdickém školení objeví osoba ze
známé-školící-firmy, aby se to naučila, bo za týden to sama
školí 🙂
Jak je na tom Jakub Vrána, jsou jeho školení doopravická? Nepopiratelně
je významná osobnost PHP scény, jeho jméno najdete dokonce v dokumentaci.
Navíc disponuje schopností přednášet, jeho výklad je srozumitelný a
působí přirozeně. A když jsem z něj ve svých školitelských
začátcích mámil know-how, shodli jsme se na tom, že jednomu kurzu věnujeme
téměř rok příprav. Splňuje tedy všechny tři body. Čtvrtý už je na
vás. Když ho splníte, tak vězte, že se školení rozhodně vyplatí.
Při psaní tohoto článku zemřelo jen zanedbatelné množství
zvířat a žádný Davídek nebyl podplacen.
Přichází trošku jako opozdilec, pro kterého včera večer
byla přichystána velkolepá oslava, ale dnes už se hosté rozešli domů.
Před rokem a půl byl internet plný článků o klíčových novinkách
v PHP 5.3, po neustálém odkládání termínů a méně příjemných
změnách nadšení vychladlo.
rozšířeny schopnosti parseru
php.ini (ale omezena flexibilita INI parseru jako takového)
odstraněn zend.ze1_compatibility_mode
To klíčové přijde v následujících týdnech: jak rychle se PHP
5.3 rozšíří? Vzhledem k tomu, že bylo vyvíjeno jako přirozený
nástupce řady 5.2 bez zpětně nekompatibilních změn, šance na brzké
rozšíření rozhodně má. Nicméně si myslím, že hostéři budou čekat,
až vyjde následující setinková verze. Jako když se u Windows čekává na
první service pack.
Historie jim přitom dává za pravdu:
PHP 5.0.0, které vyšlo s rozdílem 14 dní právě před pěti lety,
bylo použitelné cca od verze 5.0.3.
PHP 5.1.0 existovalo pouhé 4 dny a bylo nahrazeno 5.1.1, za dva
týdny 5.1.2.
PHP 5.2.0 bylo opět případem zabugované verze, kde smutnou roli sehrál
Debian.
(Totiž Debian Etch má tuto verzi předinstalovanou a nepochopitelný
konzervatismus správců vede k tomu, že odmítají PHP updatovat, bo
„jen to, co je v Debianu, je stabilní.“)