Na navigaci | Klávesové zkratky

Jak zvládnout gettery, když nemají co vrátit?

Vývoj softwaru často přináší dilema. Například jak řešit situace, kdy getter nemá co vrátit. V tomto článku prozkoumáme tři strategie pro implementaci getterů v PHP, které ovlivňují strukturu a čitelnost kódu, a každá má své specifické výhody i nevýhody. Pojďme se na ně podrobněji podívat.

Univerzální getter s parametrem

Prvním a v Nette používaným řešením je vytvoření jediné getter metody, která, pokud hodnota není dostupná, může dle potřeby vrátit buď null nebo vyhodit výjimku. O chování rozhoduje volitelný parametr. Zde je příklad, jak by mohla metoda vypadat:

public function getFoo(bool $need = true): ?Foo
{
    if (!$this->foo && $need) {
        throw new Exception("Foo not available");
    }
    return $this->foo;
}

Hlavní výhodou tohoto přístupu je, že eliminuje potřebu mít několik verzí getteru pro různé scénáře použití. Někdejší nevýhodou byla horší srozumitelnost uživatelského kódu používajícího booleovské parametry, ale ta padla s příchodem pojmenovaných parametrů, kdy lze psát getFoo(need: false).

Dále tento přístup může způsobit komplikace v oblasti statické analýzy, jelikož dle signatury se zdá, že getFoo() může vrátit null v každé situaci. Nicméně nástroje jako PHPStan umožňují explicitní dokumentaci chování metody pomocí speciálních anotací, které zlepšují porozumění kódu a jeho správnou analýzu:

/** @return ($need is true ? Foo : ?Foo) */
public function getFoo(bool $need = true): ?Foo
{
}

Tato anotace jasně určuje, jaké návratové typy může metoda getFoo() generovat v závislosti na hodnotě parametru $need. Ale například PhpStorm jí nerozumí.

Dvojice metod: hasFoo() a getFoo()

Další možností je rozdělit zodpovědnost na dvě metody: hasFoo() pro ověření existence hodnoty a getFoo() pro její získání. Tento přístup zvyšuje přehlednost kódu a je intuitivně srozumitelný.

public function hasFoo(): bool
{
    return (bool) $this->foo;
}

public function getFoo(): Foo
{
    return $this->foo ?? throw new Exception("Foo not available");

Hlavním problémem je redundance, zvláště v případech, kdy je kontrola dostupnosti hodnoty sama o sobě náročným procesem. Pokud hasFoo() provádí složité operace k ověření, zda je hodnota dostupná, a tato hodnota je poté opět získávána pomocí getFoo(), dojde k jejich opětovnému provedení. Hypoteticky může být stav objektu nebo dat změněn mezi voláním hasFoo() a getFoo(), což může vést k nesrovnalostem. Z uživatelského pohledu může být tento přístup méně pohodlný, protože nás nutí volat dvojici metod s opakujícím se parametrem. A nemůžeme využít například null-coalescing operátor.

Výhodou je, že některé nástroje pro statickou analýzu umožňují definovat pravidlo, že po úspěšném volání hasFoo() nedojde v getFoo() k vyhození výjimky.

Metody getFoo() a getFooOrNull()

Třetí strategií pro je rozdělení funkcionality na dvě metody: getFoo() pro vyhození výjimky, pokud hodnota neexistuje, a getFooOrNull() pro vrácení null. Tento přístup minimalizuje redundanci a zjednodušuje logiku.

public function getFoo(): Foo
{
    return $this->getFooOrNull() ?? throw new Exception("Foo not available");
}

public function getFooOrNull(): ?Foo
{
    return $this->foo;
}

Alternativou je dvojice getFoo() a getFooIfExists(), ale v tomto případě nemusí být zcela intuitivní pochopit, která metoda vyhazuje výjimku a která vrací null. Srozumitelnější by se jevila spíš dvojice getFooOrThrow() a getFoo().

Každý z představených přístupů k implementaci getterů v PHP má své místo v závislosti na specifických potřebách projektu a preferencích vývojářského týmu. Při výběru vhodné strategie je důležité zvážit, jaký dopad bude mít na čitelnost, údržbu a výkon aplikace. Volba by odrážet snahu o co nejsrozumitelnější a nejefektivnější kód.

Mohlo by vás zajímat

Napište komentář

Text komentáře
Kontakt

(kvůli gravataru)



*kurzíva* **tučné** "odkaz":http://example.com /--php phpkod(); \--

phpFashion © 2004, 2024 David Grudl | o blogu

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.