jooservices / exceptions
Shared exception contracts and base classes for the JOOservices ecosystem.
Requires
- php: ^8.5
Requires (Dev)
- captainhook/captainhook: ^5.24
- laravel/pint: ^1.18
- phpmd/phpmd: ^2.15
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
- squizlabs/php_codesniffer: ^3.11
This package is auto-updated.
Last update: 2026-07-22 02:31:45 UTC
README
The JOOservices Exceptions Library is a PHP 8.5+ foundational library providing shared exception contracts, base exception classes, and structured context utilities across the JOOservices package ecosystem.
Package name: jooservices/exceptions
Install
composer require jooservices/exceptions
Core Features
- Ecosystem-Wide Catching: Provide a root interface marker
JOOExceptionInterfaceto catch any exception thrown within the JOOservices ecosystem. - SPL Class Semantics Preservation: Provide separate
AbstractJOORuntimeExceptionandAbstractJOOLogicExceptionabstract bases to preserve standard PHP SPL hierarchy. - Structured Diagnostic Context: Enable context-rich logging and troubleshooting using
ContextAwareExceptionInterfaceandExceptionContext. - Sensitive Data Redaction: Intercept and mask confidential context keys at the application boundary via
ContextRedactorInterface. - Framework Decoupled: Zero external runtime dependencies. Completely agnostic and safe to use in pure PHP libraries and framework packages alike.
Basic Usage
Catching Ecosystem Exceptions
Catch any exception thrown by a JOOservices library:
use JOOservices\Exceptions\Contracts\JOOExceptionInterface; try { $dto = UserDto::from($input); } catch (JOOExceptionInterface $e) { // Handles any exception implementing JOOExceptionInterface $logger->error($e->getMessage()); }
Declaring base exceptions
Define package-level base exceptions using the appropriate base class:
use JOOservices\Exceptions\Base\AbstractJOORuntimeException; abstract class ClientException extends AbstractJOORuntimeException {}
Context-Aware Exceptions
For exceptions that need to carry structured diagnostic data (like fields, paths, or resource keys):
use JOOservices\Exceptions\Base\AbstractContextAwareException; final class HydrationException extends AbstractContextAwareException { public static function forField(string $path, string $expectedType): self { return (new self("Hydration failed for field '{$path}'")) ->withContext([ 'path' => $path, 'expectedType' => $expectedType, ]); } }
Retrieving and Logging Context
try { throw HydrationException::forField('user.email', 'string'); } catch (ContextAwareExceptionInterface $e) { $logger->error($e->getMessage(), $e->getContext()); // Context: ['path' => 'user.email', 'expectedType' => 'string'] }
Security & Context Redaction
To prevent sensitive keys (like passwords, keys, or credentials) from showing up in log systems, register a global redactor at application bootstrap:
use JOOservices\Exceptions\Base\AbstractContextAwareException; use JOOservices\Exceptions\Contracts\ContextRedactorInterface; AbstractContextAwareException::setRedactor(new class implements ContextRedactorInterface { private const SENSITIVE = ['password', 'secret', 'token', 'authorization']; public function redact(array $context): array { return array_map( fn ($key, $value) => in_array(strtolower($key), self::SENSITIVE, true) ? '[REDACTED]' : $value, array_keys($context), array_values($context), ); } });
Now, any exception extending AbstractContextAwareException will have its context keys masked when calling getContext().
Trait Integration
If an exception class cannot inherit from AbstractContextAwareException because it already inherits from a third-party class:
use JOOservices\Exceptions\Concerns\HasExceptionContext; use JOOservices\Exceptions\Contracts\ContextAwareExceptionInterface; class GuzzleWrappedException extends GuzzleException implements ContextAwareExceptionInterface { use HasExceptionContext; public function __construct(string $message, int $code = 0, ?\Throwable $previous = null) { parent::__construct($message, $code, $previous); $this->initContext(); } }
Verification
Run test suites and style linters:
composer check