Version 1 by Matthew Weier O'Phinney
on Sep 02, 2010 12:00.

compared with
Key
This line was removed.
This word was removed. This word was added.
This line was added.

Changes (14)

View Page History
* Currently, developers must rely on exception messages to understand why and/or where an exception was thrown. This has led to several requests for translatable exceptions and/or development of unique exception codes -- all of which lead to increased maintenance costs.

To illustrate, with the current situation, if we want to handle different
exceptions from the same component separately, we need to know (a) what type of
exception is thrown, and (b) some static part of the exception message:

{code:php}
try {
$someComponent->doSomething();
} catch (Some_Component_Exception $e) {
if (strstr($e->getMessage(), 'unknown')) {
// handle one type of exception
} elseif (strstr($e->getMessage(), 'not found')) {
// handle another type of exception
} else {
throw $e;
}
}
{code}

If we were to allow simply using SPL exceptions when they seem appropriate, suddenly you need multiple {{catch}} blocks to catch all possible types of exceptions for a given operation:

{code:php}
try {
$component->doSomething();
} catch (Some_Component_Exception $e) {
// handle exceptions that derive from this class
} catch (InvalidArgumentException $e) {
// handle a particular type of exception
}
{code}

What we've found is that developers typically want one of the following situations:

* Catch specific exceptions
* Catch all exceptions by component
* Catch exceptions by SPL exception type (including the base Exception class)

Our recommendation is to modify how exceptions are defined in Zend Framework 2.

* There *WILL NOT* be a top level {{Zend\Exception}} class
* Each component *WILL* define a marker {{Exception}} interface; subcomponents may optionally define a similar marker interface extending that interface.
* Exceptions *WILL* extend either {{\Exception}} or an SPL exception class, and implement the component (or subcomponent) exception interface.
* Each component *WILL* define a generic {{ComponentException}} class, extending {{\Exception}} and implementing the component level {{Exception}} marker interface.
* Exceptions extending other SPL exception classes and implementing the marker {{Exception}} interface *MAY* be created.
** Exceptions deriving from SPL exception classes *SHOULD* be named after the SPL exception they extend, but *MAY* be named uniquely. In most cases, we would recommend using the original SPL exception name to prevent a proliferation of exceptions.
* ** Exceptions not named after SPL exceptions *WILL* be named meaningfully: {{InvalidTemplateException}}, {{UnbalancedTagException}}, etc. Exception types can be re-used, but only if the name has a similar meaning in each context in which it is used.
* Because the previous requirement may lead to a proliferation of exception classes, exception classes *MAY* be grouped into an "Exception" subcomponent. The rule of thumb will be that if the number of exception classes exceeds 1/2 the number of regular classes and interfaces, they should be segregated.

|-- _autoload.php
|-- Exception
| |-- InvalidDelimiterException.php DomainException.php
| |-- InvalidEscaperException.php InvalidArgumentException.php
| |-- InvalidPartialsException.php
| |-- InvalidPragmaNameException.php
| |-- InvalidStateException.php
| |-- InvalidTemplateException.php
| |-- InvalidTemplatePathException.php
| |-- InvalidVariableNameException.php
| |-- TemplateNotFoundException.php
| |-- UnbalancedSectionException.php
| |-- UnbalancedTagException.php
| `-- UnregisteredPragmaException.php
|-- Exception.php
|-- Lexer.php
|-- Mustache.php
|-- MustacheException.php
|-- Pragma
| |-- AbstractPragma.php
{code}

{{Exception.php}} contains a single interface, {{Exception}} in the current namespace. The class {{Mustache}} throws exceptions in three several cases:

* When given an invalid template path, it throws {{Exception\InvalidTemplatePathException}}. {{Exception\InvalidArgumentException}}.
* When a bad partials alias is provided, it throws {{Exception\InvalidPartialsException}}
* When it is unable to resolve a template file, it throws {{Exception\TemplateNotFoundException}}, which extends {{\DomainException}}

While you can catch the individual exception types, it will often be easier to catch more general types. In these cases, you can use one of the SPL exception types (e.g., {{DomainException}}, {{InvalidArgumentException}}), or the marker interface for the component's exceptions (e.g., {{Zend\Markup\Exception}}):