Až nepoměrně často se v PHP kódech setkávám s jedním zlozvykem. Použitím empty
konstrukce téměř všude kde je to jen možné. Přitom je to podle mě jedna nejvíce zneužívaných věcí v PHP, která ne jen že snižuje výkon ale je i nebezpečná.
Celkem běžně je možné se setkat s PHP projekty, které v podstatě vůbec nepoužívají běžné porovnání if ($var)
místo toho je všude if (!empty($var))
a byl jsem nemile překvapen jak je tohle zakořeněné i u lidí, kteří dělají v PHP několik let a nelze je tedy považovat za začátečníky. Podle mě to vzniká tak, že to prostě někde odkoukali z nějakého podobného projektu a tak narvou empty naprosto všude, vždyť ono to funguje, tak co si s tím lámat hlavu. Dost často ani nevědí, že např. deklarované třídní proměnné mají implicitně hodnotu NULL, takže použití empty je pak naprosto zbytečné.
Další důvod bude ten, že když narazí na nějaký kód, ze kterého se sypou NOTICE chyby o nedeklarovaných proměnných nebo properties, tak tam prostě zase dají vyzkoušené empty a tak se tenhle zlozvyk dále rozvíjí a upevňuje. Tohle by ale určitě zkušenější programátor neměl dělat.
Empty je takový mladší brácha isset a společně jsou nejpoužívanějšími konstrukcemi v PHP vůbec. Což bohužel potvrzuje vžitou představu o PHP vývojářích jako bastličích. Nemá cenu popisovat k čemu vlastně tyhle konstrukce jsou jen pár vlastností, na které se těchto konstrukcí často zapomíná
- isset vrací FALSE i v případě, že proměnná existuje a má hodnotu NULL
- isset může mít více než jeden parametr
- mohlo by se zdát, že se uvnitř isset a empty se nemohou zavolat žádné funkce, ani před PHP 5.5 to nebyla tak úplně pravda
K poslednímu bodu, vždy bylo možné volat funkce a testovat až výsledná pole a objekty, např. tedy empty($this->getItems()->first["title"]); isset(filterNames("name")[0]->surname)
. Pak se také funkce mohou zavolat "skrytě", empty a isset na objektech mohou volat magické funkce __isset apod., v nich se už může dít cokoli. Možná by jste to ani neřekli, tohle
empty($sessionNamespace->items[0]);
volání nad session zavolá spousty funkcí a metod a nakonec klidně i nastartuje session.
A teď k tomu nejdůležitějšímu, proč empty nepoužívat a jaké jsou jeho vedlejší efekty
Empty vám zamaskuje překlepy
Pokud použijete
if (!empty($this->configuration["payment"][$type]["isFree"])
A v konfiguraci při nějaké úpravě změníte náhodou "payment" např. "payments", tak se klidně může stát že všichni vaši zákazníci u vás dostanou najednou všechno zdarma. Samozřejmě že jim to vadit nebude ale vašeho nadřízeného to asi moc nepotěší a on vás pak asi také moc nepotěší. Váš kód bude ale naprosto v pořádku, bez žádných chyb a NOTICES. Podobných případů a situací může být nekonečně. Tohle platí stejně pro isset.
Dvojité skryté podmínky
Zejména empty je v podstatě dvojitá podmínka, která se ovšem tváří navenek jako jedna, takže i když testy máte všechny empty volání pokryté, aplikace vám nakonec stejně nefunguje.
Empty s kladným výsledkem je vlastně zápor
Tohle je spíše subjektivní záležitost, ale řekl bych, že nebudu sám. Kód s empty je sám o sobě čitelný, ale špatně se opravuje právě tam, kde bylo empty použité zbytečně. Zápis s empty se "tváří" jako běžná funkce a většina funkcí vrací TRUE když je všechno v pořádku a FALSE, když je to chyba. Ale u empty je to přesně naopak. Už se mi párkrát stalo, že if (empty($var))
, jsem nahradil za if ($var)
, přitom správně je if (!$var)
Určitě se tedy vyplatí proměnné inicializovat, jak už několikrát poukazoval J. Vrána. Pak se výrazně redukuje použití empty i isset. Skoro bych řekl, že pokud je váš projekt prolezlý voláním empty, tak je něco špatně a měli by jste to změnit.
Osobně se pořád ještě uchyluji k tomu, že neinicializuji proměnné, které se použijí někde hluboko v zanoření nebo v cyklech
function getItems() { foreach () { if (.....) { foreach (....) { $items[] = $item; } } } return isset($items) ? $items : array(); }
Prostě proto, protože píši tak, jak se tvoří kód a neřeším nic zpětně. Zas za nějak extra velký problém to nepovažuji. Ale pokud se i v těchto případech provede inicializace před cyklem, je to určitě lepší.
Komentáře (2)
Díky za šíření osvěty. Já se tomuto problému věnuji především v článku Kdy použít isset() a kdy NULL?. Máš pravdu, že empty() je ještě větší zlo.
Empty je v php nevhodně naimplementované, o tom žádná.
a nezkušení z toho přirozeně spáchali Výsledek je prostě ostřesný, nerad čtu php kód i velkých projektů.V kódu mám rád pořádek a jsem zvyklý (z dob c/c++) psát kladné podmínky, možná špatné použití empty v php má kořeny právě tady, zkušení programátoři použili
Komentáře jsou uzavřeny.