Vyšlo PHP 5.4.0 alpha, takže je nejlepší čas se podívat na chystané změny. PHP 5.4 nepřinese tolik novinek jako PHP 5.3, změny mi ale povětšinou dělají radost.
Článek vyšel na serveru Zdroják.
PHP 5.3 označilo řadu obratů jako zastaralých, takže jejich odstranění z PHP 5.4 není žádným překvapením. Co zmizelo?
break $var;
safe_mode
a souvisejícíregister_globals
a register_long_arrays
allow_call_time_pass_reference
highlight.bg
session.bug_compat_42
a session.bug_compat_warn
y2k_compliance
session_is_registered
, session_register
a session_unregister
import_request_variables
define_syslog_variables
a stejnojmenná konfigurační direktivaŽádný z těchto obratů už léta nepoužívám, takže jejich odstranění vítám, protože do budoucna umožní zjednodušení aplikací nebo snížení nároků na jejich konfiguraci. Konfigurační direktivy magic_quotes_gpc
a magic_quotes_runtime
kupodivu přežily, i když pro první jmenovanou existuje náhrada na úrovni konfigurace a druhá se prakticky nikdy nepoužívala.
Bez náhrady zdá se zmizela i užitečná direktiva safe_mode_exec_dir
.
$_SERVER['REQUEST_TIME']
nově obsahuje i mikročas (dříve jen čas s přesností na sekundy).default_charset
v dodávaném php.ini
je UTF-8
(dříve ISO-8859-1
).array_combine(array(), array())
vrací array()
(dříve false
).preg_match_all
je nepovinný. To se hodí pro zjištění počtu výskytů regulárního výrazu.$a = null; $a->a = 1;
nyní vyvolá varování (dříve potichu prošlo).<?=
funguje nezávisle na nastavení short_open_tag
.$f = array($obj, 'method'); $f();
.f()[0]
.$this
uvnitř anonymních funkcí (netřeba uvádět v use
).zend.multibyte
(bohužel zatím není povoleno ve verzi pro Windows).http_response_code
vracející momentální HTTP status.header_register_callback
dovoluje zaregistrovat callback zavolaný těsně před posláním hlaviček.$limit
u funkcí debug_backtrace
a debug_print_backtrace
.$string[1][0]
mi sice uniká, ale aspoň už nevyvolá chybu.number_format
už dokáže zpracovat i delší oddělovače desetin a tisíců. To dovoluje použít vícebajtové kódování (např. pevnou mezeru v UTF-8) a HTML entity (např.
).hex2bin($data)
(jako protiklad k bin2hex
) je funkčně totožná s pack("H*", $data)
.I v této části jde převážně o čištění jazyka a se změnami souhlasím. Mírně kontroverzní může být <?=
, XML validita PHP skriptů ale stejně zaručena nikdy nebyla i při vypnutém short_open_tag
(např. kód <?php echo "?><"; ?>
je platný PHP skript, ale neplatný XML fragment).
Za zásadní změnu považuji zavedení konstrukce f()[0]
, která byla dlouho požadovaná a stejně dlouho odmítaná např. z důvodů horší čitelnosti. Možná se také ptáte, k čemu je z funkce vracet pole a použít z něj jediný prvek? Mně by se to kdysi hodilo v NotORM, kde byla původně metoda group
dovolující provést třeba i více agregačních funkcí najednou: list($min_id, $max_id) = $table->group("MIN(id), MAX(id)")
. Bohužel se ale neobešla bez dočasné proměnné ani v nejběžnějším případě, kdy se volala jen jedna agregační funkce. S PHP 5.4 by to šlo: $table->group("MIN(id)")["MIN(id)"]
. Nové API $table->min("id")
je ale stejně přehlednější.
Asi největší novinkou v PHP 5.4 je podpora takzvaných traits. Ty dovolují zmírnit nevýhody jednonásobné dědičnosti tím, že do třídy umožňují vložit definice metod ze společného zdroje nezávislého na dědičnosti. Hodí se to v situaci, kdy chci mít stejnou funkčnost ve více třídách bez společného rodiče. Někdy se to dá vyřešit pomocí metody __call
:
<?php class C { public $common; function __call($name, $args) { if (method_exists($this->common, $name)) { return call_user_func_array(array($this->common, $name), $args); } trigger_error("Call to undefined method " . __CLASS__ . "::$name()", E_USER_ERROR); } } ?>
Zdaleka to ale nejde vždy, např. při implementaci rozhraní s tímto přístupem nepochodíme, protože tam musí být metody definované přímo. Pak nezbývá nic jiného, než je ve třídě všechny potupně zopakovat. PHP 5.4 řeší tento problém pomocí tzv. horizontal reuse:
<?php trait T { function getIterator() { echo "T::getIterator()\n"; return new ArrayIterator($this->data); } } class C implements IteratorAggregate { public $data = array(); use T; } $c = new C; var_dump($c instanceof T); // bool(false) foreach ($c as $val) { // T::getIterator() } ?>
Změnu považuji za největší i proto, že přidává nové klíčové slovo. Možnosti jsou ještě širší, především lze definovat řešení kolizí. Zatím je funkčnost popsaná v RFC, píše se ale už i dokumentace.
Jsem zvědav, který framework začne traits využívat jako první. A také který dokumentační nástroj a které IDE se s touto novou vlastností dokáže se ctí vypořádat.
Poměrně zásadní zpětně nekompatibilní změna se týká sjednocení chování při dědění abstraktních konstruktorů s ostatními metodami. Jde o to, že když v potomkovi definujeme abstraktní metodu, musíme zachovat její parametry (můžeme jim přidat výchozí hodnotu, můžeme přidat další parametry s výchozí hodnotou, ale nemůžeme parametry odebrat nebo jim změnit typ):
<?php abstract class A { abstract function __construct($a); } class C extends A { function __construct() { } } // v PHP < 5.4 prošlo, nově vyvolá // Fatal error: Declaration of C::__construct() must be compatible with that of A::__construct() ?>
Na konstruktory se toto omezení nevztahovalo, což nová verze opravuje (a tím zároveň sjednocuje chování s deklarováním konstruktoru pomocí rozhraní). Tento obrat se přitom občas používal, do dokumentace první alpha verze se ale popis této změny bohužel nedostal.
Už delší dobu se dají informace o průběhu nahrávání souborů od uživatele zobrazovat pomocí extenze APC. Nově to jde i jen pomocí session proměnných. Vzniklo k tomu několik konfiguračních direktiv začínajících na session.upload_progress.
, pomocí kterých se dá chování ovlivnit.
Pokud je sledování průběhu nahrávání povoleno, tak už stačí jen metodou POST poslat pole s názvem ini_get("session.upload_progress.name")
. To způsobí vytvoření proměnné $_SESSION[ini_get("session.upload_progress.prefix") . $_POST[ini_get("session.upload_progress.name")]]
, která bude obsahovat pole se všemi dostupnými informacemi. Detailně to rozebírá příklad.
scandir
nyní dovoluje netřídit výsledek. Tuto funkci jsem už nicméně dávno vyměnil za šikovnější glob
.Spoofchecker
kontrolující zaměnitelné řetězce, např. "http://www.payp\xD0\xB0l.com"
.mysql_list_dbs
. Výsledky mysqli_result
lze konečně procházet pomocí foreach
.ReflectionClass::isCloneable
, ReflectionExtension::isPersistent
a ReflectionExtension::isTemporary
. Vznikla třída ReflectionZendExtension
.session.entropy_file
je /dev/urandom
nebo /dev/arandom
, pokud tyto „soubory“ existují v době kompilaci PHP.RegexIterator::getRegex
, SplObjectStorage::getHash
a třídy CallbackFilterIterator
a RecursiveCallbackFilterIterator
.V extenzi JSON, která je v poslední době velmi populární, je změn více:
JsonSerializable
deklarující metodu JsonSerializable::jsonSerialize
, jejíž výstup se předá funkci json_encode
.json_decode
nově umí vracet velká čísla jako řetězce – to se může hodit třeba u Twitter API. Funkce json_encode
se obdobně naučila převádět číselné řetězce na JSON čísla.json_encode
nyní dokáže výstup formátovat pomocí bílých znaků a nemusí ošetřovat znak /
.--rz
poskytující informace o Zend extenzích (obdoba třídy ReflectionZendExtension
).cli.pager
a cli.prompt
.#inisetting=value
, platí to ale jen při práci přes Readline.Kromě těchto změn, které jsou důležité při vytváření aplikací, došlo také k řadě vylepšení ve výkonnosti a paměťové náročnosti PHP. V méně používaných extenzích došlo k několika dalším změnám, které tento článek nepopisuje.
Když už lze volat f()[]
, tak bych také ocenil obrat (new C)->f()
, který by se hodil u fluent interface. Nemožnost pracovat s výsledkem operátoru new
se dá různými způsoby obejít, je to ale značně krkolomné:
<?php // první možnost function identity($x) { return $x; } identity(new C)->f(); // druhá možnost class C { static function create() { return new self; } } C::create()->f(); ?>
Této vlastnosti bychom se v PHP 5.4 měli ještě dočkat.
Občas by se mi také hodilo deklarovat návratový typ metod. Užitečné by to bylo hlavně u dědičnosti, kdy by se dalo odvozeným třídám přikázat, aby vracely stejný typ objektu. Této změny se podle mě zatím nedočkáme.
Vydaná alpha na mě působí celkem vyzrálým dojmem. Pár chyb se sice již objevilo, ale věřím, že nebudou nijak závažné a další vývojová verze vyjde poměrně brzy. Změny na mě také působí poměrně uceleným dojmem, takže si myslím, že příliš dalších novinek se v PHP 5.4.0 už neobjeví.
Diskuse je zrušena z důvodu spamu.