Skip to content

php-enspired/exceptable

Repository files navigation

how exceptable!

A lot of php code treats exceptions in an ad-hoc way: throwing a plain Exception instance with a message written inline. Then, when (...if?) you look at your error log, you have to start working backwards to figure out the state of the application at that time.

Exceptables make exceptions exceptional. Exceptables are:

  • ✓ easy to create and pass details to
  • ✓ are readable by both humans and your application code
  • ✓ can provide a wealth of runtime information about the state of things that led to the problem
  • ✓ make it easy to add, adapt, and maintain error handling code as your application grows

More importantly, when throwing an Exceptable, you can include any additional information that might be helpful - values of arguments or local variables, details about state, whole objects, anything! This context is good for adding details to the error message, but can also be sent to log aggregation tools, and even be used at runtime to inspect the error and recover or fail gracefully.

dependencies

Requires php 8.2 or later.

ICU support requires the intl extension.

installation

Recommended installation method is via Composer:

simply composer require "php-enspired/exceptable:^5"

a quick taste

<?php

use at\exceptable\ {
  Error,
  IsError
};

// a simple Error, just for you
enum ProcessError : int implements Error {
  use IsError;

  case NotReady = 1;
  public const MESSAGES = [
    self::NotReady->name => "{type} is not ready (status is '{status}')"
  ];
}

class Example {
  public function __construct( public string $status ) {}
}

$example = new Example("preparing");
if ($example->status !== "ready") {
  throw (ProcessError::NotReady)([
    "type" => $example::class,
    "status" => $example->status
  ]);
}

outputs:

Fatal error: Uncaught at\exceptable\Spl\RuntimeException: ProcessError.NotReady: Example is not ready (status is 'preparing')

errors as values

Having errors available to your application as normal values also means you can decide to not throw exceptions.

The Result pattern, for example, is a functional programming approach to error handling that treats error conditions as normal, expected return values. This encourages handling error cases more carefully and closer to their source, and is also a benefit to static analysis. See Larry Garfield's excellent article ("A Naked Result") for more.

<?php

use at\exceptable\ {
  Error,
  IsError
};

enum FooError : int implements Error {
  use IsError;

  case TheyToldMeToDoIt = 1;
  public const MESSAGES = [
    self::TheyToldMeToDoIt->name => "ooh noooooooooooooooooo!"
  ];
}

function foo(bool $fail) : string|FooError {
  return $fail ?
    FooError::TheyToldMeToDoIt :
    "woooooooooooooooooo hoo!";
}

$bool = maybeTrueMaybeFalse();
$result = foo($bool);
if ($result instanceof FooError) {
  echo $result->message();
  // outputs "ooh noooooooooooooooooo!"

  $bool = ! $bool;
  $result = foo($bool);
}

echo $result;
// outputs "woooooooooooooooooo hoo!"

...and if you want to make everybody mad, you can still throw them.

throw $result(["yes" => "i know i'm horrible"]);

see more in the wiki.

Version 5.0

Version 5 requires PHP 8.2 or greater.

  • ICU messaging system overhauled and published to its own package! Check out php-enspired/peekaboo - using exceptable means you get it for free, so take advantage!
  • Introduces the Error interface for enums, making errors into first-class citizens and opening up the ability to handle errors as values. Adds an SplError enum for php's built-in exception types.
  • Reworks and improves functionality for Exceptables and the Handler. Error / Exception / Shutdown Handlers now have explicit interfaces, as do debug log entries.

Read the release notes.

Version 4.0

Version 4.0 requires PHP 7.4 or greater.

  • PHP 7.4 added typehints to some Throwable properties, which required changes to the IsExceptable trait. This means Exceptable can no longer support PHP 7.3 or earlier - though that's fine, right? You've already upgraded your application to 8+ anyway, right?
  • right?

docs

Usage

Api

contributing or getting help

I'm on IRC at libera#php-enspired, or open an issue on github. Feedback is welcomed as well.

About

Augmented features for exceptions and exception handling.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages