40

Creating Exception types on-the-fly in modern PHP - Matthew Weier O'Phin...

 5 years ago
source link: https://www.tuicool.com/articles/hit/veeimaf
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

We pioneered a pattern for exception handling for Zend Framework back as we initially began development on version 2 around seven years ago. The pattern looks like this:

  • We would create a marker ExceptionInterface for each package.
  • We would extend SPL exceptions and implement the package marker interface when doing so.

What this gave users was the ability to catch in three ways:

  • They could catch the most specific exception type by class name.
  • They could catch all package-level exceptions using the marker interface.
  • The could catch general exceptions using the associated SPL type.

So, as an example:

try {
    $do->something();
} catch (MostSpecificException $e) {
} catch (PackageLevelExceptionInterface $e) {
} catch (\RuntimeException $e) {
}

This kind of granularity is really nice to work with. So nice that some standards produced by PHP-FIG now ship them, such as PSR-11 , which ships a ContainerExceptionInterface and a NotFoundExceptionInterface .

One thing we've started doing recently as we make packages support only PHP 7 versions is to have the marker ExceptionInterface extend the Throwable interface; this ensures that implementations must be able to be thrown!

So, what happens when you're writing a one-off implementation of something that is expected to throw an exception matching one of these interfaces?

Why, use an anonymous class, of course!

As an example, I was writing up some documentation that illustrated a custom ContainerInterface implementation today, and realized I needed to throw an exception at one point, specifically a Psr\Container\NotFoundExceptionInterface . I wrote up the following snippet:

$message = sprintf(/* ... */);
throw new class($message) extends RuntimeException implements
    NotFoundExceptionInterface {
};

Done!

This works because RuntimeException takes a message as the first constructor argument; by extending that class, I gain that behavior. Since NotFoundExceptionInterface is a marker interface, I did not need to add any additional behavior, so this inline example works out-of-the-box.

What else are you using anonymous classes for?

Posted by Matthew Weier O'Phinney ,


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK