Debugger: odstranění tryError, catchError a toStringException

před 7 lety

David Grudl
Nette Core | 6864
+
+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 ;-)

před 7 lety

Filip Procházka
Moderator | 4693
+
0
-

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

před 7 lety

David Grudl
Nette Core | 6864
+
0
-

Vyzkoušej to.

před 7 lety

Filip Procházka
Moderator | 4693
+
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.

před 7 lety

David Grudl
Nette Core | 6864
+
0
-

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