Problematika hierarchie a použití výjimek v PHP
Zdroje
Doporučuji přečíst nejprve následující dva články a kouknout na existující výjimky, které jsou definovány v SPL v PHP.
Obecné rozdělení výjimek
- Usage error (důležitý je text výjimky, nikoliv typ; lze mu předejít na místě, kde je metoda volána)
- System error
- Logical error (důležitý je typ výjimky pro přesné zachytávání; nelze jim předejít)
- System failures (nezachytávají se)
(Podrobněji je to popsáno v prvním výše odkázaném článku.)
Výjimky v PHP
- Dynamic call
- Runtime = nelze zachytit kontrolou argumentů
- Logic = neplatný argument
(Podrobněji popsáno v druhém výše odkázaném článku.)
Logic
DomainException(value does not adhere to a defined valid data domain)InvalidArgumentException(an argument does not match with the expected value)LengthException(length is invalid)OutOfRangeException(value does not match with a range)
Runtime
OutOfBoundsException(value is not a valid key)OverflowException(adding an element into a full container)RangeException(an invalid range is given)UnderflowException(trying to remove an element of an empty container)UnexpectedValueException(value does not match with a set of values)
Ukázkový příklad
V třídě RegistrationManager existuje metoda
activateUser, která slouží k aktivaci účtu uživatele pomocí
odkazu, který dostane po registraci e-mailem. Metoda má dva parametry –
$userId a $activationKey.
Seznam problémů, které mohou nastat
- Parametry mají nesprávný tvar. (Např.
$userIdnení číslo nebo$activationKeynemá správný počet znaků.) - Uživatel s daným
$userIdneexistuje. - Uživatel s daným
$userIdmá účet již aktivovaný. - Aktivační klíč je neplatný.
Požadavky na řešení
- Při odchytávání chyb musí být možné od sebe jednotlivé chyby jednoznačně rozlišit.
- Zprávy ve výjimkách jsou pro programátora. Informační texty pro uživatele se sestavují až v presenteru a nesmí být závislé na zprávách ve výjimkách.
Rozbor jednotlivých problémů
Parametry mají nesprávný tvar
- Usage error → Logická chyba
- Použil bych
InvalidArgumentException(SPL) s popisnou zprávou. - Pro nesprávný počet znaků v parametru
$activationKeyby šla použít iLengthException, ale vadí mi, že nedědí odInvalidArgumentException.
Uživatel s daným ID neexistuje
- Runtime chyba
- Nelíbí se mi žádná výjimka z SPL ani z Nette. (Pokud bych si musel
vybrat, tak nejbližší mi přijde
UnexpectedValueExceptionz SPL aInvalidStateExceptionz Nette.) - Vytvořil bych tedy nějakou vlastní výjimku, asi
EntityNotFoundException(extends RuntimeException). Napadá vás nějaký lepší název?
Uživatel s daným ID má účet již aktivovaný
- Runtime chyba
- Použil bych asi
InvalidStateException(Nette).UnexpectedValueExceptionz SPL by ale asi taky šla, ale kolidovala by s výjimkou pro neplatnost aktivačního klíče.
Aktivační klíč je neplatný
- Runtime chyba
- Použil bych asi
UnexpectedValueException(SPL), ale nejsem si moc jist, zda to odpovídá její definici (a value does not match with a set of values). Spíš by seděla definice zInvalidArgumentException(an argument does not match with the expected value), jenomže ta nedědí odRuntimeException. - Nebo vytvořit novou výjimku
InvalidActionKeyException?
Další poznámky
- V PHP lze kromě typu výjimky rozlišovat jednotlivé chyby i pomocí chybového kódu. To např. C# nemá. Nepodařilo se mi najít žádnou Best Practice, jak s kódy výjimek pracovat.
- Co dělat v případě, že v metodě jsou dvě místa, kde může dojít
k
EntityNotFoundExceptiona potřebujeme je rozlišit?- Použít kód výjimky jako prosté číslo – fuj!
- Použít kód výjimky jako konstantu
RegistrationManageru– asi můj favorit - Použít kód výjimky jako konstantu potomka
EntityNotFoundException– Jak se bude jmenovat? Stejně s rozlišením pomocí jmenných prostorů? - Vytvořit dvě nové výjimky dědící od
EntityNotFoundException
- V budoucnu se mohou objevit další místa, kde bude vhodné vyhodit stejnou výjimku, jako na nějakém jiném řádku. Není lepší od začátku všude rvát kódy výjimek? S tím souvisí otázka, kam s konstantami, které tyto kódy reprezentují.
Jak řešíte problematiku použití výjimek vy? Řešili byste ukázkový příklad jinak?
Článek byl publikován 31. 12. 2010 02:33