stygian91/php-cordyceps

0.3.0 2024-06-16 08:44 UTC

This package is auto-updated.

Last update: 2024-09-16 09:24:42 UTC


README

Cordyceps 是一个小型包,提供了两个主要的类:用于处理 null 值的 Option 和用于处理错误的 Result

Option

Option 是一个包装可能为 null 的值的包装器,这允许我们在每次可能返回 null 值的操作之后减少需要执行的 null 检查次数。在我们完成所有的操作之后,我们才需要解包内部值并检查它是否确实存在。

示例

<?php
// this:
function myFunc($arg) {
    $value1 = somethingThatCouldBeNull1($arg);
    if (is_null($value1)) {
        return null;
    }

    $value2 = somethingThatCouldBeNull2($value1);
    if (is_null($value2)) {
        return null;
    }


    $value3 = somethingThatCouldBeNull3($value2);
    if (is_null($value3)) {
        return null;
    }

    // use $value3
}

// ------------
// becomes this:
function myFunc2($arg) {
    $option = Option::make(somethingThatCouldBeNull1($arg))
        // Any callable works here, you can pass regular functions, anon functions and class methods
        // the same way you'd pass them to `call_user_func_array`.
        ->map('somethingThatCouldBeNull2')
        ->map('somethingThatCouldBeNull3')
        ->map(function ($value) {
            // use final $value
        });

    // At the end you *will* need to unwrap the value to see if the chain succeeded.
    // You can query if the wrapped value is "something" or "nothing" with $option->isSome() and $option->isNone().
    // $option->unwrap() will return the wrapped value, be it null or not.
    // If you want to provide a fallback value, you can use $option->unwrapOr($fallback).
    // You can also lazily evaluate the fallback value by using $option->unwrapOrElse(fn () => 'fallback value').
}

Result

Result 是一个包装器,使将错误作为值处理变得更加容易。这是 try/catch 的替代方案,将错误作为值处理的主要好处是,当真正解包可能成为您的“绿色路径”值或错误的值时,您会提醒自己操作可能会失败。而忘记进行 try/catch 非常容易。

示例

<?php

// this:
function thisCouldGoWrong1($arg) {
    // ...
    if (somethingIsWrong($arg)) {
        throw new Exception('oops');
    }

    return 'some value';
}

function thisCouldGoWrong2($arg) {
    // ...
    if (somethingIsWrong2($arg)) {
        throw new Exception('oops 2');
    }

    return 'some value 2';
}

try {
    $res = thisCouldGoWrong1(42);
    $res = thisCouldGoWrong2($res);
} catch (\Throwable $th) {
    // handle error
}

// ------------
// becomes this:
function thisCouldGoWrong1($arg) {
    // ...
    if (somethingIsWrong($arg)) {
        return Result::makeErr(new Exception('oops'));
    }

    return Result::makeOk('some value');
}

function thisCouldGoWrong2($arg) {
    // ...
    if (somethingIsWrong($arg)) {
        return Result::makeErr(new Exception('oops 2'));
    }

    return Result::makeOk('some value 2');
}

$res = thisCouldGoWrong1(42)
    // just like Option, you can pass anything that would fit in `call_user_func_array`
    ->andThen('thisCouldGoWrong2');

if ($res->isErr()) {
    $exception = $res->unwrap();
    // handle the exception
} else {
    $value = $res->unwrap();
}

// or if you want, you can provide a fallback value, like you can with option:
$value = $res->unwrapOr('fallback');
// or lazily-evaluated version:
$value = $res->unwrapOrElse(fn () => 'fallback');

这对于我们的代码来说都很好,但是当我们不得不调用旧代码或第三方代码,这些代码会抛出异常时,我们该怎么办呢?您可以使用 Result::try() 将可能抛出异常的可调用包装起来。

示例

<?php

// Result::try's arguments are the same as call_user_func_array
$res = Result::try('thisCouldThrow', ['func arg', 'func arg 2']);
if ($res->isErr()) {
    // handle error
}