Když getter nemá co vrátit

David Grudl
Nette Core | 8206
+
0
-

Řeším otázku, jak v Nette sjednotit přístup k tomu, když getter nemá co vrátit. Může to být klidně Nette\PhpGenerator\ClassType::getMethod() nebo BaseControl::getForm() atd.

Nette převážně používalo tohle řešení:

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

Má to výhodu v tom, že si vystačí s jednou metodou a podle situace se můžeme rozhodnout, zda chceme výchozí výjimku nebo vrátit null. Dříve byl určitou nevýhodou bool parametr, neboť bool parametry obecně jsou v kódu srozumitelné, ale tohle padlo od příchodu pojmenovaných argumentů. Větším problémem je statická kontrola, která nedokáže dvojí chování rozlišit a pak upozorňuje, že metoda vrací null. Nicméně PHPStan už to třeba umí:

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

Dvojice has & get

Alternativní možnost je mít dvojici metod

  • hasFoo(): bool
  • getFoo(): Foo

Tedy getFoo() bude vždy vyhazovat výjimku, které lze předejít voláním hasFoo(). Problém s tímto přístupem je, že v některých situacích je ověřit existenci a získat podobně složitý úkol, který se tak vlastně odehrává zbytečně dvakrát. A z pohledu uživatele je tu nutnost volat obě metody se stejným parametrem – pokud bych chtěl použít nějaký výraz, musel bych si jej uložit do proměnné. Výhodou je existence funkce has, která vypadá srozumitelněji v podmínkách.

Dvojice get() a getIfExists()

Třetí možností je dvojice metod:

  • getFoo(): Foo
  • getFooIfExists(): ?Foo

První vyhazuje výjimku, druhá vrací null. Tahle varianta řeší problémy zmíněné u dvojice has & get. Zkusil jsem tohle řešení kdysi použít v Nette právě kvůli (tehdejším) problémům se statickou analýzou, a to v Presenteru a třídě User, ale uvědomil jsem si, že se mi vlastně něčím nelíbí… Že parametr $need mi připadal elegantnější.

Co si o tom myslíte vy?

stpnkcrk
Generous Backer | 190
+
+1
-

Mně nejvíc vyhovuje logika get/getIfExists. Zvykl jsem si s tím pracovat při používání Nextras Orm, kde jsou např. metody getBy/getByChecked na získání entity z repozitáře (checked varianty vyhazují výjimky).

Editoval stpnkcrk (13. 5. 12:45)

mystik
Člen | 304
+
+2
-

Proc ne oboje? Vzdycky mit has/get/getIfExists

Ale pokud bych si mel vybrat tak asi get/getIfExists

Šaman
Člen | 2655
+
+3
-

Při práci s databází používám:

  • get() : vrať právě jeden záznam, jinak výjimka
  • find() : vrať co najdeš, může to být i null

Takže spíš preferuji tu logiku get|getIfExists.

hrach
Člen | 1836
+
+11
-

Ja preferuji tu treti variantu, akorat bych doporucil Kotlin-naming:

  • get()
  • getOrNull()
Infanticide0
Člen | 100
+
-3
-
/** @throws NotFoundException */
function get(): Foo;

function tryGet(): ?Foo;