Debugger: odstranění tryError, catchError a toStringException

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
David Grudl
Nette Core | 8218
+
+1
-

Nette interně používalo dvojici metod Debugger::tryError & catchError pro zachycení E_NOTICE nebo E_WARNING a jejich následné zpracování a také metodu Debugger::toStringException řešící problém, že v PHP se nesmí vyhodit výjimka v metodě __toString().

Pokud jste tyto metody používali, vězte, že jsou označeny jako deprecated a budou v dalších verzích odstraněny.

Důvod je především ten, že vytvářely závislost na třídě Debugger. Z hlediska čistoty a přenositelnosti kódu je taková závislost kontraproduktivní. Podstatné však je, že dnes lze stejného výsledku dosáhnout i bez těchto metod.

tryError & catchError

Klasický use case vypadal takto:

		Nette\Diagnostics\Debugger::tryError(); // zachytávání chyb
		$ini = parse_ini_file($file, TRUE); // funkce, která může generovat E_WARNING
		if (Nette\Diagnostics\Debugger::catchError($e)) { // pokud došlo k chybě, bude převedena na výjimku
			throw new InvalidArgumentException('parse_ini_file(): ' . $e->getMessage(), 0, $e);
		}

bez Debuggeru se dá věc zapsat takto:

		set_error_handler(function($severity, $message) { // zachytávání chyb
			restore_error_handler();
			throw new InvalidArgumentException("parse_ini_file(): $message"); // konverze na výjimku
		});
		$ini = parse_ini_file($file, TRUE); // funkce, která může generovat E_WARNING
		restore_error_handler(); // ukončení zachytávání chyb

Výsledný kód takřka stejně dlouhý, jen vyhození výjimky se trošku nelogicky nachází nad volanou funkcí. Závislost na Debuggeru je ale pryč.

Pokud je chyba signalizovaná návratovou hodnotou, lze použít ještě jednodušší řešení:

		$ini = @parse_ini_file($file, TRUE); // funkce, která může generovat E_WARNING
		if ($ini === FALSE) {
			$error = error_get_last();
			throw new InvalidArgumentException("parse_ini_file(): $error[message]"); // konverze na výjimku
		}

toStringException

Use case vypadal takto:

	public function __toString()
	{
		try {
			return $this->toString();

		} catch (\Exception $e) { // výjimka se nesmí vyhodit
			Diagnostics\Debugger::toStringException($e); // necháme ji zobrazit Debuggerem
		}
	}

bez Debuggeru se dá zapsat takto:

	public function __toString()
	{
		try {
			return $this->toString();

		} catch (\Exception $e) {// výjimka se nesmí vyhodit
			trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()}", E_USER_ERROR);
		}
	}

Výsledný kód je opět stejně dlouhý, nicméně bez závislosti na Debuggeru a tedy přenositelný. Co je podstatné, tak že na funkčnosti to nijak neubralo, protože Debugger dokáže situaci detekovat, dostane se k výjimce a zobrazí ji stejně jako dosud. Kdybych vymyslel dřív, jak tohoto dosáhnout, toStringException() by vůbec nevznikla ;-)

Filip Procházka
Moderator | 4668
+
0
-

A co případný stack trace z metody toString? O ten přijdu.

David Grudl
Nette Core | 8218
+
0
-

Vyzkoušej to.

Filip Procházka
Moderator | 4668
+
0
-

Vyzkoušel jsem

  1. WTF
  2. It's Magic!

Je to super no :) Jen nevím kolik % lidí odchytává výjimky do $e. Určitě víc jak půlka, ale těžko říct.

David Grudl
Nette Core | 8218
+
0
-

Analyzoval jsem různé kódy a dělá to 99 %.