A PHP 5.3 -ban bevezettek egy nem nagyon hangoztatott operátort. Aminek a függvény alakja az „ifsetor” névre hallgatott volna. Azt viszont elvetették a fejlesztők. Az operátor hasonló a már rég ismert és más nyelvekben is használt ternáris operátorhoz.
echo $x ?: $default;
Gyakorlatilag a következő kód rövidítése:
echo $x ? $x : $default;
Tehát:
echo $x ?: 20;
Kiírja, hogy 20, mert az $x logikai hamissá konvertálható. De a
echo $x ?: 20;
Kiírja, hogy 12, mert az $x itt már logikai típusként igaz értéket venne fel.
Persze személy szerint azt hiszem, ezzel kaptunk egy nem túl hasznos, ámde érdekes operátort. Ugyanis erre így nem gyakran van szükség. Talán csak a következő példát tudnám most hirtelen elképzelni:
$v = (int)$array[array_rand($array)];
echo 'A kisorsolt szám: '. ( $v ?: 'Nem szám!' );
Ezzel gyakorlatilag két karakternyit spóroltam ( persze, lehetne hosszabb a változóm neve... ). Sokkal gyakoribb viszont szerintem, amikor az sem biztos, hogy létezik az a bizonyos változó, vagy csak üres. Például, amikor URL-ből kapjuk a megjelenítendő oldal nevét.
echo !empty($_GET['page']) ? $_GET['page'] : 'home';
Tekintsünk el attól, hogy egyébként is kellene itt más vizsgálat is élesben! A fenti kódot így írhatnám:
echo $_GET['page'] ?: 'home';
De nem írhatom, mert a nem létező page index miatt notice hibaüzenet jön ugyanúgy, mint eme hasznos operátor nélkül is, ha nem használok empty-t vagy isset-et. Kukaccal elnyomhatnám a hibaüzenetet, de tudni kell, hogy a kukac használata nem csak nem szép, de lassú is. Nézzük a következő példákat feltételezve, hogy a page változó létezik az url-ben.
for($i=0; $i<1000; $i++)
{
$tmp = $_GET['page'] ? $_GET['page'] : 'home';
}
$now = microtime(true);
echo '<br />'. ($now - $time);
Eredmény: 0.000931978225708
De:
for($i=0; $i<1000; $i++)
{
$tmp = @$_GET['page'] ? $_GET['page'] : 'home';
}
$now = microtime(true);
echo '<br />'. ($now - $time);
Eredmény: 0.00180101394653
Tehát majdnem kétszer lassabb kódot eredményez. Nyilván ez ekkora számoknál nem tűnik jelentősnek. Most nézzük ugyanezt a kódot az empty használatával.
$tmp = !empty($_GET['page']) ? $_GET['page'] : 'home';
Eredmény: 0.000945091247559
Ismét egy gyorsabb kódot kaptam. De vajon lehet-e ezen is gyorsítani? Látható, hogy az empty „függvény” pontosan azt adja vissza, hogy a változó nem létezik ( vagy hamissá konvertálható ). Tehát ha nem terhelem a felkiáltójeles tagadással, picit még gyorsabb lehet.
$tmp = empty($_GET['page']) ? 'home' : $_GET['page'];
Eredmény: 0.0008769035339361
Nézzük akkor most azt, amikor a változó nem létezik az url-ben. Ekkor a sok hibaüzenet kimenetre küldése lelassítaná a programot, ezért én a tesztben ob_start()
és ob_clean()
függvényekkel eldobom a kimenetet.
$time = microtime(true);
for($i=0; $i<1000; $i++)
{
$tmp = $_GET['page'] ? $_GET['page'] : 'home';
}
$now = microtime(true);
ob_clean();
echo '<br />'. ($now - $time);
Eredmény: 0.013188123703
Most nézzük kukaccal:
$tmp = @$_GET['page'] ? $_GET['page'] : 'home';
Eredmény: 0.00254011154175
Majd pedig ugyanezt a empty használatával.
$tmp = empty($_GET['page']) ? 'home' : $_GET['page'];
Eredmény: 0.000745058059692
Itt feltűnhet, hogy a kukac még gyorsított is a kódon. De még mindig nem annyit, mintha empty-t használtam volna. Na most ehhez képest, ha én a cikk elején említett ?:
operátort használom, a sebesség semmit nem változik. Tehát még ezt sem lehet előnyére írni. Az empty-t használó megoldás tehát minden tekintetben gyorsabbnak tűnik. Viszont hosszabb leírni. Erre lehetne függvényt írni, ahol referenciaként várjuk a változót ( így nem lenne notice hibaüzenet ), de az meg a függvényhívások miatt lassítana. De hogy felhozzak a ?:
operátor mentségére is valamit, van, amikor mégiscsak hasznos. Van ugyanis már egy függvény a hasonló megoldásokra. Az pedig a filter_input
.
for($i=0; $i<1000; $i++)
{
$tmp = filter_input(INPUT_GET, 'page') ?: 'home';
}
$now = microtime(true);
echo '<br />'. ($now - $time);
Eredmény: 0.00311899185181
Itt szebb, mintha kiírnám újra a függvényhívást. ( és egyébként gyorsabb is, de ez most mellékes ). Ha pedig a ciklusból kiveszem a függvényhívást, ami úgyis ugyanazt adja vissza, akkor:
$page = filter_input(INPUT_GET, 'page');
for($i=0; $i<1000; $i++)
{
$tmp = $page ?: 'home';
}
$now = microtime(true);
echo '<br />'. ($now - $time);
Eredmény: 0.000550985336304
Ezzel elérkeztünk a leggyorsabb, és valószínűleg a legszebb megoldáshoz. Összességében nem tartom így sem hasznosnak ezt az új operátort. Annyit nem lehet vele spórolni, hogy hiányozzon. Így azon sem csodálkozom, hogy a php.net-en sem lehet róla olvasni. Habár már elég régen létezik és csak egy 2005-ös konferencia összegzésében olvastam róla. A PHP-ben sok mindent lehet ma már. A beépített függvények általában gyorsabbak, mint a sajátok, ha adott függvény pontosan azt és csak azt teszi, amire szükségünk van. Nem azt mondom, hogy be kell magolni és naponta figyelni és böngészni a netet és a dokumentációt. De időről időre jobb körülnézni akár céltalanul is. Hátha rábukkanunk valami hasznosra.