Článek vyšel na serveru Root.cz.
PHP 5.3 obsahuje nejvíce změn ze všech minoritních verzí, které kdy PHP vydalo. Důvodem je skutečnost, že vývojáři PHP se rozhodli do této verze přesunout téměř všechny novinky původně plánované pro PHP 6 s výjimkou podpory Unicode. Vývoj trval velmi dlouho (původně bylo vydání naplánováno na podzim 2007) a byl poměrně bolestivý kvůli několika změnám v jeho průběhu.
php.ini
Jmenné prostory dovolují oddělit jednotlivé části programu tak, že i když obsahují stejnojmenné identifikátory, nebudou vzájemně kolidovat. Potřeba jmenných prostorů se naléhavě ukázala při vydání PHP 5.1, které obsahovalo třídu date, která kolidovala s PEAR knihovnou Date.
Pro definici jmenného prostoru se používá nové klíčové slovo namespace. To lze použít buď v syntaxi se složenými závorkami nebo jednoduše ukončit středníkem – potom bude ve jmenném prostoru obsažen veškerý následující kód. Syntaxe je tedy stejná jako u málo známé konstrukce declare (tu je možno nově použít i k určení kódování souboru, bez speciální kompilace ale volba slouží zatím jen k získání dopředné kompatibility s PHP 6).
V jednom souboru lze definovat více jmenných prostorů, to se ale využije asi jen zřídka. Naopak stejný jmenný prostor může být nastaven ve více souborech, takže je možno zachovat konvenci jednoho souboru na jednu třídu a přitom všechny mohou sdílet stejný jmenný prostor.
Pokud chceme použít třídu, funkci nebo konstantu z cizího jmenného prostoru, můžeme tak učinit předřazením jeho identifikátoru a zpětného lomítka. Jako oddělovač se v průběhu vývoje používala čtyřtečka, kvůli nejednoznačnosti ale byla nahrazena (znamená A::f()
statickou metodu ve třídě A
nebo funkci ve jmenném prostoru A
?). Uvažovalo se o šestitečce, zaslechl jsem návrh ležaté dvojtečky (..
), ale zpětné lomítko nakonec vychází asi nejlépe. Jen jsem zvědav, jak si s ním poradí editory zdrojového kódu…
Jmenné prostory lze vytvářet hierarchicky oddělením jednotlivých komponent pomocí zpětného lomítka. Pro zjednodušení práce s takovýmito jmennými prostory lze použít klíčové slovo use které importuje jmenný prostor pod identifikátorem jeho poslední části. Za use je navíc možné přiřadit klauzuli as, která dovoluje zpřístupnit jmenný prostor pod aliasem.
<?php // knihovna.inc.php namespace Knihovna\Komponenta { class Trida { function __construct() { echo "OK\n"; } } } // index.php include "./knihovna.inc.php"; new Knihovna\Komponenta\Trida; // OK use Knihovna\Komponenta\Trida as T; new T; // OK ?>
Některé funkce PHP přijímají tzv. callback parametry – funkce nebo metody, které se zavolají v určitém okamžiku. Jsou to např. funkce preg_replace_callback, array_map, ob_start nebo session_set_save_handler. PHP na místě těchto parametrů dovoluje předat globální funkci (předáním řetězce) nebo metodu nějakého objektu (předáním pole array($obj, 'metoda')
). Funkci je možné vytvořit i přímo na místě pomocí create_function, s tím je ale spojeno potenciální bezpečnostní riziko (pokud bychom v definici funkce použili neošetřená data od uživatele) a výkonnostní hendikep, kód se navíc zapisuje do řetězce, takže v něm v editorech nefunguje ani zvýrazňování syntaxe.
PHP 5.3 dovoluje funkci definovat přímo na místě podobně, jako to umožňuje např. JavaScript – uvedením klíčového slova function, vynecháním názvu funkce a připojením parametrů a těla funkce.
<?php $s = 'hello-world'; echo preg_replace_callback('~-([a-z])~', function ($match) { return strtoupper($match[1]); }, $s); ?>
Uplatnění vidím hlavně u jednoduchých jednořádkových operací, kde je definice globální funkce samoúčelná. Užitečné je samozřejmě i to, že jednoúčelová funkce nepřekáží mezi obecně použitelnými funkcemi.
Anonymní funkce mohou používat i proměnné nadřazeného objektu. Na rozdíl od JavaScriptu ale nejsou vidět všechny proměnné, nýbrž jen ty, které explicitně uvedeme v klauzuli use:
<?php $separator = "-"; $s = 'helloWorld'; echo preg_replace_callback('~[A-Z]~', function ($match) use ($separator) { return $separator . strtolower($match[0]); }, $s); ?>
Anonymní funkce jsou interně reprezentovány jako objekty třídy Closure
, která obsahuje metodu __invoke
. Tuto metodu můžeme nadefinovat i u vlastních tříd, takže pak objekty odvozené z těchto tříd můžeme používat v kontextu funkce:
<?php class Ahoj { function __invoke($s) { echo "Ahoj $s!\n"; } } $ahoj = new Ahoj; $ahoj("světe"); ?>
PHP vyhodnocuje klíčové slovo self při kompilaci, takže následující kód vypíše Trida
a nikoliv Potomek
, jak by se možná na první pohled zdálo:
<?php class Trida { static $a = 'Trida'; static function f() { return self::$a; } } class Potomek extends Trida { static $a = 'Potomek'; } echo Potomek::f(); // Trida ?>
K vyřešení tohoto problému dovoluje použít PHP 5.3 u statických metod místo self klíčové slovo static, které použitou třídu vyhodnotí až při běhu:
<?php class Trida { static $a = 'Trida'; static function f() { return static::$a; } } class Potomek extends Trida { static $a = 'Potomek'; } echo Potomek::f(); // Potomek ?>
Pro přetížení volání statických metod přibyla magická metoda __callStatic. Ta se zavolá vždy, když se pokusíme staticky zavolat nedefinovanou metodu nějaké třídy. Stejně jako metoda __call dostane název metody a předané argumenty.
<?php class Trida { static function __callStatic($nazev, $argumenty) { echo "$nazev\n"; } } Trida::f(); ?>
Operátoru pro podmíněný výraz se obvykle říká ternární operátor, tento pojem ale vyjadřuje jen počet operandů (podobně jako u binárních a unárních operátorů) a je jen náhoda, že je v PHP jen jeden. Výraz ($if ? $true : $false)
vrátí $true
, pokud je podmínka $if
splněna, jinak vrátí $false
.
PHP 5.3 dovoluje prostřední část vynechat, takže výraz ($if ?: $false)
vrátí $if
, pokud je podmínka $if
splněna, jinak vrátí $false
. V JavaScriptu se stejně chová obyčejný operátor ||
, který vrátí první pravdivou složku (v PHP tento operátor vrací true nebo false).
Zkrácený podmíněný výraz bohužel není obdobou funkce IFNULL a když je podmínka nedefinovaná, tak vyvolá chybu úrovně E_NOTICE stejně jako jakákoliv jiná práce s neinicializovanou proměnnou. Obdobu této funkce si můžeme sami vytvořit pro pole, kde je tato vlastnost nejčastěji potřeba:
<?php function vychozi($pole, $klic, $vychozi) { return (isset($pole[$klic]) ? $pole[$klic] : $vychozi); } echo htmlspecialchars(vychozi($_GET, "search", "")); ?>
Po vášnivých debatách přibyl do PHP 5.3 příkaz goto. Slouží k přesunu na jiné místo kódu a uplatnění má především pro ošetření chybových stavů, osobně ho ale používat nebudu. Příkaz neumožňuje přeskočit dovnitř cyklu nebo příkazu switch.
<?php function f($filename) { $fp = fopen($filename, 'r'); $error1 = true; if ($error1) { goto clean; } return $fp; clean: fclose($fp); return false; } ?>
PHP dovoluje řetězec zapsat třemi způsoby:
Heredoc jsem nikdy neměl v oblibě, protože jako jediná syntaktická konstrukce v PHP je platformově závislá (používá nativní ukončovač řádku) a oproti uvozovkám přináší jen nepatrnou výhodu (konec řádku lze totiž na rozdíl od mnoha jiných jazyků v PHP použít i uvnitř apostrofů a uvozovek). Heredoc naopak nelze použít na všech místech (např. při deklaraci vlastností třídy).
V PHP 5.3 přibyl čtvrtý způsob definice řetězce, tzv. nowdoc syntaxe. Ta je podobná jako heredoc, ale neinterpretují se proměnné a zpětné lomítko nemá žádný význam. Heredoc bez proměnných lze navíc nově použít i u statických proměnných a třídních vlastností a konstant. Pro nowdoc se používá syntaxe <<<'EOT'
, pro heredoc přibyla vedle stávající <<<EOT
také alternativní syntaxe <<<"EOT"
.
<?php echo <<<'EOT' '$x:\' EOT; ?>
PHP používá pro uvolňování paměti jednoduchý algoritmus počítání referencí. Pokud se na sebe vzájemně odkazují dvě proměnné, vzniká cyklus, který tento algoritmus nedokáže nalézt, takže proměnné zůstanou v paměti až do konce běhu skriptu. To je problém hlavně u dlouhoběžících skriptů.
V rámci Google Summer of Code byl implementován algoritmus, který tyto cykly dokáže detekovat. Tento algoritmus je součástí PHP 5.3 a protože skripty mírně zpomaluje, dá se vypnout funkcí gc_disable nebo konfigurační direktivou zend.enable_gc.
PHP ve všech extenzích pro práci s MySQL (MySQL, MySQLi, PDO) používá univerzální knihovnu libmysql. Tato knihovna má několik nevýhod, proto PHP 5.3 přichází s novou knihovnou MySQLnd, kterou lze použít místo libmysql. Knihovna navenek nijak nemění API (kromě několika přidaných funkcí) a je tedy zpětně kompatibilní se staršími verzemi.
Hlavním přínosem knihovny MySQLnd je to, že data získaná od MySQL serveru ukládá přímo do struktur, které používá PHP. Knihovna libmysql naproti tomu data ukládá do vlastních struktur, které je před použitím v PHP potřeba převést, což stojí jednak čas a jednak paměť (data jsou uložena dvakrát). MySQLnd navíc data stejně jako PHP kopíruje až když to je potřeba, takže přiřazení řádku s výsledkem do proměnné nestojí téměř žádnou paměť. Podle dostupných informací by se navíc paměť zabraná MySQLnd měla počítat do memory_limit, to se mi ale nepodařilo potvrdit a i zdrojový kód vypadá, že místo emalloc používá malloc, které se do paměťového limitu nezapočítává. Nakonec to je možná dobře, protože řada hostingů má nastavené nesmyslně nízké paměťové limity a náhlé započítání paměti zabrané knihovnou (která se zabírá stejně, jen to není tak snadno vidět) by řadu aplikací vyřadilo z provozu.
Knihovna přidává i několik funkcí:
<?php $link1 = mysqli_connect(); $link2 = mysqli_connect(); $link1->query("SELECT 'test1'", MYSQLI_ASYNC); $link2->query("SELECT 'test2'", MYSQLI_ASYNC); $all_links = array($link1, $link2); $processed = 0; do { $links = $errors = $reject = array(); foreach ($all_links as $link) { $links[] = $errors[] = $reject[] = $link; } if (!mysqli_poll($links, $errors, $reject, 1)) { continue; } foreach ($links as $link) { if ($result = $link->reap_async_query()) { print_r($result->fetch_row()); mysqli_free_result($result); $processed++; } } } while ($processed < count($all_links)); ?>
Extenze MySQLi se přidává ke zbylým dvěma extenzím a zavádí možnost persistentního připojení. Nevznikla sice funkce mysqli_pconnect, ale názvu serveru u funkce mysqli_connect lze předřadit p:
, což vytvoření persistentního připojení zajistí. Většina nevýhod persistentního připojení zůstala, ale alespoň ta hlavní díky automatickému zavolání funkce mysqli_change_user zmizela (při připojení se ukončí transakce, odemknou tabulky a odstraní dočasné tabulky).
Několik extenzí bylo také odstraněno.
favicon.ico
.dirname(__FILE__)
, které se používá především při vkládání skriptů, lze nově použít konstanta __DIR__.php.ini
php.ini
lze přidávat sekce, které dovolují upravit chování v závislosti na doméně nebo cestě k souboru..htaccess
). Slouží k tomu konfigurační direktiva user_ini.filename
, jejíž výchozí hodnota je .user.ini
.php.ini-development
a php.ini-production
a prodělaly několik změn, z nichž asi nejdůležitější je vypnutí magic_quotes_gpc i ve vývojářské konfiguraci. Výchozí hodnota session.use_only_cookies byla změněna na zapnuto.V PHP 5.3 došlo také k několika interním změnám, které by měly vést ke zvýšení výkonnosti. Podle prvních testů se zdá, že se to podařilo.
$this
.PHP 5.3 přináší neobvykle vysoké množství změn a dá se považovat téměř za plánované PHP 6 bez podpory Unicode a bez odstranění zastaralých obratů. Ještě více než kdy jindy se tedy nejspíš vyplatí s nasazením chvilku počkat, protože se jako již tradičně s nulovou verzí dají očekávat nějaké problémy (i když testovací fáze byla neobvykle dlouhá). Všechny změny se také postupně dostávají do oficiálního manuálu a jsou popsané v oficiální dokumentaci.
Diskuse je zrušena z důvodu spamu.