Mirin webspace

Nejbohatší život má ten, kdo žije s minimem nároků

30. 8. 2015 - Komentáře (2) PHP

Do háje s empty

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)

  1. Tomáš - 31. 8. 2015 23:48

    Empty je v php nevhodně naimplementované, o tom žádná.

    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

    if(empty($var))
    a nezkušení z toho přirozeně spáchali
    if(!empty($var))
    Výsledek je prostě ostřesný, nerad čtu php kód i velkých projektů.

Komentáře jsou uzavřeny.