Traits a další novinky v PHP 5.4
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.
Odstranění zastaralých obratů
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?
- Konstrukce
break $var;
- Konfigurační direktiva
safe_mode
a související - Konfigurační direktivy
register_globals
aregister_long_arrays
- Konfigurační direktiva
allow_call_time_pass_reference
- Konfigurační direktiva
highlight.bg
- Konfigurační direktivy
session.bug_compat_42
asession.bug_compat_warn
- Konfigurační direktiva
y2k_compliance
- Funkce
session_is_registered
,session_register
asession_unregister
- Funkce
import_request_variables
- Funkce
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
.
Nové vlastnosti
$_SERVER['REQUEST_TIME']
nově obsahuje i mikročas (dříve jen čas s přesností na sekundy).- Výchozí hodnota konfigurační direktivy
default_charset
v dodávanémphp.ini
jeUTF-8
(dříveISO-8859-1
). array_combine(array(), array())
vracíarray()
(dřívefalse
).- Třetí parametr funkce
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
.- Podpora nepřímého volání metod:
$f = array($obj, 'method'); $f();
. - Přístup k prvku pole vráceného funkcí:
f()[0]
. - Možnost použít
$this
uvnitř anonymních funkcí (netřeba uvádět vuse
). - Možnost zpracovat zdrojáky ve vícebajtovém kódování pomocí
zend.multibyte
(bohužel zatím není povoleno ve verzi pro Windows). - Funkce
http_response_code
vracející momentální HTTP status. - Funkce
header_register_callback
dovoluje zaregistrovat callback zavolaný těsně před posláním hlaviček. - Parametr
$limit
u funkcídebug_backtrace
adebug_print_backtrace
. - Smysl konstrukce
$string[1][0]
mi sice uniká, ale aspoň už nevyvolá chybu. - Některé funkce dříve specifické pro Apache jsou nyní k dispozici i pod FastCGI.
- Funkce
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ř.
). - Funkce
hex2bin($data)
(jako protiklad kbin2hex
) je funkčně totožná spack("H*", $data)
. - Finální verzre přidala kratší definici polí:
$a = [1, 2]
. - Finální verzre přidala binární čísla:
0b0110
.
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ší.
Traits
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.
Zákaz změny parametrů u abstraktních konstruktorů
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.
Informace o průběhu uploadu souborů
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.
Změny v extenzích
- V cURL lze omezit rychlost stahování a odesílání dat.
- Funkce
scandir
nyní dovoluje netřídit výsledek. Tuto funkci jsem už nicméně dávno vyměnil za šikovnějšíglob
. - Do extenze Hash přibyly hašovací funkce Joaat a FNV-1.
- Do extenze Intl přibyla třída
Spoofchecker
kontrolující zaměnitelné řetězce, např."http://www.payp\xD0\xB0l.com"
. - Z MySQL zmizela funkce
mysql_list_dbs
. Výsledkymysqli_result
lze konečně procházet pomocíforeach
. - OpenSSL nově podporuje šifrování pomocí AES.
- Reflexi přibyly metody
ReflectionClass::isCloneable
,ReflectionExtension::isPersistent
aReflectionExtension::isTemporary
. Vznikla třídaReflectionZendExtension
. - Výchozí hodnota
session.entropy_file
je/dev/urandom
nebo/dev/arandom
, pokud tyto „soubory“ existují v době kompilaci PHP. - V SPL přibyly metody
RegexIterator::getRegex
,SplObjectStorage::getHash
a třídyCallbackFilterIterator
aRecursiveCallbackFilterIterator
.
V extenzi JSON, která je v poslední době velmi populární, je změn více:
- Přibylo rozhraní
JsonSerializable
deklarující metoduJsonSerializable::jsonSerialize
, jejíž výstup se předá funkcijson_encode
. - Funkce
json_decode
nově umí vracet velká čísla jako řetězce – to se může hodit třeba u Twitter API. Funkcejson_encode
se obdobně naučila převádět číselné řetězce na JSON čísla. - Funkce
json_encode
nyní dokáže výstup formátovat pomocí bílých znaků a nemusí ošetřovat znak/
.
Změny příkazové řádky
- Přibyla volba
--rz
poskytující informace o Zend extenzích (obdoba třídyReflectionZendExtension
). - Dále vznikly konfigurační direktivy
cli.pager
acli.prompt
. - V interaktivním režimu by také mělo fungovat nastavování konfiguračních direktiv pomocí
#inisetting=value
, platí to ale jen při práci přes Readline.
Další novinky
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.
Co mi ještě chybí
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.
Závěr
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
Emil:
Hustej mazec..Hacafrakus:
V knize je bohužel už napsáno v příkladu 273<?php
// returnArray()[0]; // Syntaktická chyba
?>
Připsal bych to někam do chyb v knize - není to teda chyba, ale hodí se vědět, že to teď jde.
Jakub Vrána
:
Díky za upozornění. Opravil jsem si to ve zdrojácích knihy (které by se případně použily pro druhé vydání).


korek:
f()[0] konečně, good job. traits jistě taky najdou svoje využití, ale že by konečně zavedli named parameters u funkcí, to ne
Jakub Vrána
:
set_magic_quotes_runtime(0) přežilo, set_magic_quotes_runtime(1) hází fatální chybu. To je myslím rozumné řešení.


Diskuse je zrušena z důvodu spamu.

