Namespace TH\Maybe

Option

Type Option represents an optional value: every Option is either Option\Some and contains a value, or Option\None, and does not. Option types have a number of uses:

Options are commonly paired with instanceof Option\{Some|None} to query the presence of a value and take action, always accounting for the None case.

Examples

// @return Option<float>
function divide(float $numerator, float $denominator): Option {
  if ($denominator === 0.0) {
    return Option\none();
  }

return Option\some($numerator / $denominator);
}

// The return value of the function is an option
$result = divide(2.0, 3.0);

// Use instanceof to differentiate between Some & None
if ($result instanceof Option\Some) {
  // The division was valid
  echo "Result: {$result->unwrap()}";
} else {
  echo "Cannot divide by 0";
}
// @prints Result: 0.66666666666667

Result

Result<T, E> is the type used for returning and propagating errors. It two variants, Ok(T), representing success and containing a value, and Err(E), representing error and containing an error value.

Functions return Result whenever errors are expected and recoverable.

A simple function returning Result might be defined and used like so:

// @param Result<int,string>
function parse_version(string $header): Result {
    return match ($header[0] ?? null) {
        null => Result\err("invalid header length"),
        "1" => Result\ok(1),
        "2" => Result\ok(2),
        default => Result\err("invalid version"),
    };
}

$version = parse_version("1.x");
if ($version->isOk()) {
    echo "working with version: {$version->unwrap()}";
} else {
    echo "error parsing header: {$version->unwrapErr()}";
}
// @prints working with version: 1
Results must be used

A common problem with using return values to indicate errors is that it is easy to ignore the return value, thus failing to handle the error. Unused Results are tracked and will trigger an exception when a Result value is ignored and goes out of scope. This makes Result especially useful with functions that may encounter errors but don’t otherwise return a useful value.

// Write $data in $filepath
// @return Result<int,string> The number of bytes that were written to the file if Ok, an error message otherwise
function writeInFile(string $filepath, string $data): Result {
    $res = @file_put_contents($filepath, $data);

if ($res === false) {
        return Result\err("failed to write in $filepath");
    }

return Result\ok($res);
}

writeInFile("/path/to/file", "Hi!");
// @throws TH\Maybe\Result\UnusedResultException Unused Result dropped

Using a Result can be done by calling any method on it, except inspect() & inspectErr().

Note: some methods return another Result that must also be used.

TH\Maybe\Option

TH\Maybe\Result