Skip to content

Add a predicate-based throwable filtering adapter #5

Closed

Description

@coisa

Delivered status

This opt-in 2.x feature is complete. Owner coisa merged PR68 at a709ec85b679e46bc422e7acd63654764dcfa633; that PR natively closed this issue. Handler\FilteringThrowableHandler shipped in v2.1.0 and remains present in current master/v2.4.1.

The implementation preserves PHP 7.4, the typed constructor, legacy integration and default discovery. The explicit boolean predicate controls delivery to its delegate; predicate/delegate failures propagate. Focused unit tests, full PHPDoc, the executable filtering recipe, guides/site and consumer skill were delivered together. PR86 now exposes the complete source-checked recipe.

The following investigation records the original alternatives and acceptance questions. Its proposal wording and unchecked historical checklist do not mean this closed feature awaits another implementation.

Historical investigation

Summary & intent

Investigate a small predicate decorator that forwards selected throwables to a reporter. It should make reusable routing explicit while preserving the existing PHP suppression, HTTP rendering and lifecycle contracts.

Status: potential opt-in 2.x minor after compatibility-preserving tooling/CI. Keep PHP 7.4 syntax/resolution and the legacy container/ConfigProvider/defaults; no filtering default is introduced. See the staged roadmap.

Findings & constraints

Observed fact Design consequence
CallableThrowableHandler already supports application-defined filtering Keep one-off cases simple; justify a reusable decorator through composition
PHP-error conversion already honors error_reporting() and @ Filter already-created throwables; never rewrite global error masks
The proposed major reports before pure rendering; 2.x derives a response body from output capture Do not assume that future separation exists: filter private diagnostic branches and verify the legacy HTTP composition explicitly
ErrorException::getSeverity() carries PHP severity Do not treat arbitrary exception codes as severity or HTTP status

Alternatives & trade-offs

Alternative Complexity Breaking risk Maintenance cost Assessment
Application callable only Low None Repeated local predicates Valid status quo
A small predicate decorator Low Additive One focused adapter Recommended investigation
Routing through existing event listeners Medium None Requires event composition Useful when routing is already event-based
General rules engine/configuration DSL High Broad policy surface Substantial Outside this issue; no demonstrated need

Proposed strategy

Evaluate FilteringThrowableHandler with a ThrowableHandlerInterface delegate and callable(Throwable): bool predicate. A match delivers the same object once; a nonmatch returns normally. Predicate and delegate failures propagate; neither causes implicit retry.

Keep the decorator outside the default aggregate and preserve handleThrowable(): void. Applications supply the predicate explicitly; autowiring must not invent one. Constructor order and final naming should follow the library's composition conventions.

This is intentional diagnostic filtering, not exception recovery. A nonmatch does not mean the application operation succeeded, and HTTP rendering still handles the original downstream failure.

Isolated investigation & validation

In a disposable branch/worktree, compose the decorator with a recording reporter and the existing middleware. Use synthetic ordinary exceptions and ErrorException severities. Check that the predicate runs once, matches preserve identity/order, nonmatches skip only the delegate, and existing callback restoration remains unchanged. Preserve the known 2.x lifecycle behavior; this decorator does not add the major's guard.

No process-wide masks, real production errors or global suppression configuration should be changed. If the decorator does not simplify composition, retain a tested callable example and discard the isolated implementation.

Guiding questions

  • Is true always “forward”, and is that obvious in the chosen name?
  • Should the predicate accept only Throwable, with richer routing kept application-owned?
  • Which examples make intentional suppression clear without encouraging broad loss of diagnostics?

Acceptance criteria

  • Freeze predicate semantics, constructor order and naming with concise PHPDoc.
  • Cover match/nonmatch, predicate failure, delegate failure, original-object identity, one invocation and relevant lifecycle/recursion boundaries.
  • Prove diagnostic filtering leaves HTTP response selection and PHP suppression semantics intact.
  • Add a runnable example and update English README, API/provider/cookbook/static-site docs, relevant migration guidance and coisa-error-handler skill in the same PR.
  • Include a Changeset; pass the retained 2.x runtime range including the PHP 7.4 minimum, supported dependency bounds, composer --no-plugins check, source parity and production autoload/archive validation.
  • Keep configuration and registration explicit; introduce no rule engine or automatic filtering policy.

Related proposals: direct PSR-3, best effort.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions