Článek vyšel v rámci PHP okénka na serveru Root.cz.
PHP 5.1 slibuje podobně jako každá větší verze téměř jakéhokoliv produktu významné zrychlení, aktualizované knihovny a spoustu dalších oprav a vylepšení. Některé novinky jsou ale významnější a vyplatí se na ně podívat podrobněji.
Asi nejvýznamnější novinkou v PHP 5.1 je rozšíření PDO umožňující jednotným způsobem pracovat s rozličnými databázemi. Na rozdíl od knihoven ADOdb nebo PEAR DB se nesnaží vytvořit kompletní abstrakci skrývající rozdíly mezi jednotlivými databázemi, ale naopak k nim poskytuje nízkoúrovňový přístup se všemi jejich specifickými vlastnostmi pomocí jednotného rozhraní. Používání PDO je samozřejmě doporučované a přestože klasická rozšíření pro práci s databázemi zatím nejsou označená jako zastaralá (v některých případech obsahují širší funkčnost), jednou k tomu pravděpodobně dojde. Pokud chcete pracovat např. s databází SQLite 3, jiná možnost už ani neexistuje, pro práci s MySQL jsou naopak možnosti hned tři – klasické MySQL, MySQLi pokrývající funkčnost verze 4.1 a právě PDO.
Prvním příkazem při práci s databází je inicializace – u databázových serverů to je připojení k nim, u SQLite otevření souboru. V PDO k tomu slouží konstruktor, kterému se předává DSN a případně uživatelské jméno a heslo. Překvapuje mě, že některým databázím se jméno a heslo předává přímo v DSN a jiným jako další parametry, ale asi to je dáno způsobem, jakým se s databází komunikuje.
<?php $pdo = new PDO("mysql:dbname=test"); ?>
Trochu mě také zaskočilo množství funkcí pro pokládání dotazů. Zatímco rozšíření MySQL nabízí jedinou funkci mysql_query, v PDO jsou k dispozici hned tři:
<?php // vrátí počet ovlivněných řádek echo $pdo->exec("INSERT INTO test (jmeno) VALUES ('Franta')"); // vrátí PDOStatement, který lze přímo procházet foreach ($pdo->query("SELECT * FROM test") as $row) { echo "$row[jmeno]\n"; } // vázání proměnných $result = $pdo->prepare("SELECT * FROM test WHERE jmeno LIKE ?"); $result->execute(array('Franta')); while ($row = $result->fetch(PDO::FETCH_ASSOC)) { echo "$row[jmeno]\n"; } ?>
Za pozornost stojí, že výsledky lze procházet jak tradičním while ($row = $result->fetch())
, tak přímo konstrukcí foreach. Myšlenka vázání proměnných se mi líbí, ale protože často kladu dotaz s jedinou sadou parametrů, tak postrádám možnost v jedné funkci určit jak SQL dotaz, tak předané parametry. Za účelem vyřešení těchto drobných nedostatků jsem vytvořil skromné rozšíření:
<?php /// rozšíření třídy PDO, které umožňuje předávání spouštěcích parametrů metodám query() a exec() class MyPDO extends PDO { public function query($statement, $input_parameters = array()) { $result = $this->prepare($statement); $result->setFetchMode(PDO::FETCH_ASSOC); return ($result && $result->execute($input_parameters) ? $result : false); } public function exec($statement, $input_parameters = array()) { $result = $this->query($statement, $input_parameters); return ($result ? $result->rowCount() : false); } } ?>
Při použití vázání proměnných je záhodno vypnout direktivu magic_quotes_gpc, jinak se do databáze uloží nadbytečná zpětná lomítka.
Vázání proměnných je velice užitečný koncept zvyšující bezpečnost skriptů, ale doporučuji se obloukem vyhnout jeho implementaci funkcemi PDOStatement::bindParam a PDOStatement::bindColumn. Funkce by měly mít jasně definovaný vstup v podobě parametrů a výstup v podobě návratové hodnoty. V odůvodněných případech lze výstup předávat i skrze parametry, ale rozhodně je lepší se uvnitř funkce vyhnout používání globálních proměnných a obzvláště jejich modifikaci. Zmíněné dvě funkce způsobí, že různé PDO funkce budou měnit hodnotu nastavených globálních proměnných, což může u trochu složitějších skriptů vést k nepříjemným a těžko odhalitelným chybám.
Do PHP 5.1.0 se bohužel přes všech 6 RC dostala chyba (v CVS už opravená) způsobující, že exec v MySQL vrací vždy pouze 0 nebo -1. Představené rozšíření používá metodu rowCount, která touto chybou netrpí.
Pro vytváření složitějších rozšíření se může hodit atribut PDO::ATTR_STATEMENT_CLASS, který dovoluje nastavit potomka třídy PDOStatement, který následně bude vytvářen místo PDOStatement. Hodnota parametru je pole array("Název třídy", array("parametry konstruktoru"))
. Použití bez přidání jakékoliv funkčnosti je tedy následující:
<?php class MyPDOStatement extends PDOStatement { private function __construct() { } } $pdo = new PDO("mysql:dbname=test"); $pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, array("MyPDOStatement", array())); ?>
V PHP 5.1 byla z velké části přepracovaná práce s datem, díky čemuž např. začal fungovat negativní timestamp i pod Windows, které ho nativně nepodporují. Funkce by se navenek měly chovat stejně, ale nově respektují časové pásmo nastavené direktivou date.timezone nebo novou funkcí date_default_timezone_set. Doposud bylo možné časové pásmo ovlivnit pouze proměnnou prostředí TZ a k práci s časem se používaly systémové knihovny, což způsobovalo nekompatibilitu mezi různými platformami. Nová je i funkce strptime převádějící řetězec na datum. Na rozdíl od funkce strtotime je u ní možné nastavit formát data.
Nově je také definováno několik konstant pro pohodlnější generování standardních formátů dat. Tyto konstanty jsou umístěny do třídy date, jejíž název bohužel koliduje s knihovnou PEAR Date, která existuje už tři a půl roku a která je poměrně hojně používaná. Je to o to smutnější, že třída date zatím nedefinuje žádné metody (byť je to v plánu). Pokud tuto nebo jinou stejnojmennou třídu používáte, můžete do konfigurace přidat disable_classes = date
.
Knihovna PCRE, která se v PHP používá pro kontrolu Perl-kompatibilních regulárních výrazů, je průběžně vylepšována. V dokumentaci například chyběla zmínka o tom, že konstrukci \x
je možné v UTF-8 režimu (při použití přepínače u
) používat ve tvaru \x{…}
, kde uvnitř složených závorek je hexadecimální číslo Unicodového znaku.
Do PHP 4.4.0 a 5.1.0 byla zakompilovaná verze s rozšířenou podporou Unicode, takže je možné kontrolovat rozličné vlastnosti Unicodových znaků. Například \pL
strefí jakékoliv písmeno (s diakritikou i bez).
Poměrně nenápadnou a asi zřídka používanou novinkou bude nová řídící struktura __halt_compiler, která zastaví zpracování PHP instrukcí. Hodí se především pro vytváření skriptů přímo obsahujících data, např. instalačních programů. Na rozdíl od konstrukce exit, která ukončí zpracování skriptu, se za konstrukcí __halt_compiler nepokračuje ani v parsování, takže následující data nemusí vyhovovat PHP syntaxi. Na začátek dat odkazuje konstanta __COMPILER_HALT_OFFSET__. Konstanta odkazuje na první znak za koncem příkazu, který obvykle ukončuje středník, takže by data musela začínat ještě na stejném řádku. Využít se dá toho, že příkaz lze ukončit i značkou ?>
a volitelným koncem řádku.
<?php // jednoduchý instalátor $fp = fopen(__FILE__, "r"); fseek($fp, __COMPILER_HALT_OFFSET__); while (($filename = trim(fgets($fp)))) { $length = trim(fgets($fp)); file_put_contents($filename, fread($fp, $length)); } fclose($fp); __halt_compiler() ?> a.php 18 <?php echo 'a'; ?>
offset
a maxlen
), preg_replace a preg_replace_callback (parametr count
), explode (negativní hodnota parametru limit
) a substr_count (parametry offset
a length
).`php -l`
nebo novou funkci runkit_lint, pro tu je ale potřeba povolit samostatné rozšíření.${direktiva}
.I přes velkou snahu QA týmu vydat verzi, která by byla bez chyb, se to bohužel nepodařilo. Kromě zmíněných chyb v PDO::exec a Digest autentizaci bude v PHP 5.1.1 možná odstraněn nebo přejmenován konfliktní objekt date. Kontroverzní upozornění na zastaralost {}
pro přístup ke znakům řetězce naštěstí mezi RC 6 a ostrou verzí zmizelo.
Přestože tedy PHP 5.1 přináší poměrně užitečné novinky, vyplatí se s přechodem myslím počkat až na PHP 5.1.1. Vzhledem k tomu, že současná verze obsahuje i bezpečnostní záplaty, tak se vydání opravy doufejme příliš neprotáhne.
Diskuse je zrušena z důvodu spamu.