juststeveking/result
A lightweight Result type for PHP and Laravel. Return success or failure values instead of throwing exceptions, chain transformations, and handle errors explicitly. Supports ok/err creation, mapping, and unwrapping for clearer, safer, more testable control flow.
Result/Either class, it standardizes success/failure as a first-class value. This is the primary product decision it unlocks.Result::ok() / Result::err() and unwrap() / expect() let a PM push teams toward explicit, typed failure paths in business logic rather than relying on exceptions for expected outcomes (validation failures, not-found, payment declines). That's a reliability and observability lever, not just a code-style preference.result_match() and map/andThen make it straightforward to define how a domain operation's outcome is translated at the boundary (HTTP response, job retry, event emission). A PM can use this to standardize "what does failure look like" across services.andThen/orElse/tap/tapErr support readable pipelines for onboarding, checkout, ingestion, or any multi-stage process where you want to short-circuit on the first failure while preserving the error. Useful for deciding whether to model a flow as a pipeline versus a saga/state machine.tap / tapErr give a sanctioned place to log, emit metrics, or record analytics without polluting the happy path — a product-quality decision about instrumenting failure paths.ComparableResult for int|string Ok values supports idempotency checks and "did this already succeed?" decisions in jobs and webhooks.null or throw to signal "expected" failure.Adopt when:
mixed, enums-friendly codebase) and already run PHPStan or Psalm — the package's value is largely realized through static analysis.Result to responses, redirects, retries, and logs.Result/Either semantics to set conventions, or you're willing to invest in a short internal style guide.Look elsewhere or defer when:
ValidationException / Handler / abort() patterns and migration cost outweighs the benefit.1.0.0, single-maintainer package; treat it as a small, auditable dependency rather than infrastructure.Risk notes for the adoption decision: verify the released API surface and PHP version constraints in composer.json, confirm the test suite and PHPStan baseline pass in your PHP version matrix, and check the license. Because global helper functions are autoloaded (ok(), err(), result_match()), audit for name collisions with existing helpers before rollout — that's the one realistic upgrade hazard.
For executives (one paragraph): This is a small, free, dependency-free PHP package that standardizes how our code represents "succeeded" versus "failed." It doesn't add infrastructure, a service, or a vendor relationship — it's a coding convention with a library behind it. The business case is reduced blast radius from unexpected failures: expected failures (bad input, declined payment, upstream timeout) become explicit, typed, and consistently logged and handled, instead of being thrown as exceptions and caught wherever convenient. Cost is low and reversible; the main investment is a short internal standard and a thin adapter to translate results into HTTP responses and job outcomes. Recommended as a pilot on one service before broader adoption, with a review at the end of the pilot.
For engineering leadership:
Low-risk, high-leverage primitive. Framework-agnostic, no service provider, no config, no runtime dependencies. Ships PHPUnit tests, PHPStan strict rules, and Pint formatting, plus PHPDoc generics for real static-analysis support — which means adopting it also nudges us toward stricter typing in CI. Main caveats: it's a 1.0.0 from a single maintainer, so pin the version and treat it as a reviewed dependency; and it deliberately omits Laravel HTTP/queue glue, so we own a small mapping layer. Recommend mandating it only in the domain/service layer, not as a replacement for Laravel's validation and HTTP exception handling at the edges.
For the engineering team:
Use Result::ok/Result::err for expected, recoverable outcomes in domain and service code. Use andThen for multi-step flows, tap/tapErr for logging and metrics, result_match at boundaries to produce a response or dispatch. Prefer expect() over unwrap() in application code so failures carry context. Wrap it with a small Result → JsonResponse / Result → job release adapter so controllers and jobs stay thin. Don't wrap genuinely exceptional conditions; if you can't recover from it, throw. Write a one-page style guide and add a PHPStan rule set before rollout, and audit for collisions with existing ok() / err() helpers.
How can I help you explore Laravel packages today?