Skip to content

Why Maybe?

Maybe exists to make the two most common sources of runtime surprise in PHP — null and exceptions used as control flow — visible in the type of a value, so the compiler-in-your-head (and your reviewer) can see them.

The cost of null

null is the value that fits everywhere and means nothing. A function returning ?User forces every caller to remember a check that the type doesn't enforce:

php
$user = $repo->find($id);
echo strtoupper($user->name()); // fine until $user is null in production

Option<User> makes absence a case you must handle, not one you can forget:

php
$repo->find($id)
    ->map(fn (User $u) => strtoupper($u->name()))
    ->unwrapOr('unknown');

The cost of exceptions as control flow

Exceptions are great for unexpected failures. Used for expected ones — a declined payment, an invalid coupon, a business rule — they turn ordinary outcomes into invisible jumps that don't show up in a signature:

php
function charge(Order $o): string       // can this throw? you have to read the body

Result<string, PaymentError> puts the failure in the return type, and match() forces both paths to be handled at the boundary:

php
charge($order)->match(
    fn (string $ref) => "paid: {$ref}",
    fn (PaymentError $e) => "declined: {$e->reason()}"
);

Exceptions still belong to genuinely unexpected failures (broken config, I/O outages). Maybe is for the expected ones.

What Maybe gives you

Five building blocks that share one philosophy — make success, failure, and absence explicit and typed:

  • Option — optional values without scattered null checks.
  • Result — success/error as data, composed with andThen/orElse.
  • Schema — parse untrusted input into validated data at the boundary.
  • DTO — give validated data a name and a type.
  • Async — process-based concurrency with no extensions required.

How it compares

Maybe is not the only option, and it isn't trying to beat specialists at their own game. Its niche is one integrated toolkit that runs where legacy PHP lives — PHP 7.4, Windows, CodeIgniter 3.

You want…Specialist toolsWhere Maybe fits
Just Optionphpoption/phpoptionMaybe bundles it with Result/Schema/DTO under one style and package.
Just ResultGrahamCampbell/Result-TypeSame — plus andThen/orElse/okOption and a shared error philosophy.
Rich validationrespect/validation, symfony/validator, Zod (JS)Schema is smaller and returns a Result; pair it with andThen for cross-field rules.
Heavy asyncspatie/async, amphp, reactphpAsync targets PHP 7.4 + Windows with no pcntl/extensions; simpler, not a full event loop.

Maybe's edge: the five blocks are designed to compose with each other (a Schema returns a Result, a DTO wraps a Schema, an Option converts to a Result), in a single dependency that installs on PHP 7.4.

When not to use Maybe

Honesty first — reach for something else when:

  • You're on modern PHP (8.1+) and already standardized on a mature specialist library you're happy with.
  • You need a full async event loop with non-blocking I/O — use amphp/reactphp, not Async.
  • You need a validation engine with a large built-in rule catalog and i18n messages out of the box — symfony/validator or respect/validation may fit better.
  • Your team strongly prefers exceptions and won't adopt Result at boundaries — the value comes from consistent use.

If you're maintaining legacy PHP, want typed success/error paths, and value one small, framework-agnostic dependency, that's exactly what Maybe is for.

Next: the Tutorial builds a real validated flow end to end, or jump to the API Reference.