martyrer/throwless-php
Composer 安装命令:
composer require martyrer/throwless-php
包简介
A PHP library for exception-free error handling using the Result monad pattern
README 文档
README
A PHP implementation of the Result type pattern, inspired by Rust's Result and JavaScript's neverthrow library. This library provides a type-safe way to handle errors without relying on exceptions, making your code more predictable and easier to reason about.
Features
- Type-safe error handling without exceptions
- Immutable Result type with
OkandErrvariants - Comprehensive set of methods for working with Results
- Pure functional programming approach
- PHP 8.2+ with strict typing support
Installation
composer require martyrer/throwless-php
Available Methods
-
isOk()- Check if the Result contains a success valueisErr()- Check if the Result contains an error valueisOkAnd(callable $fn)- Executes the closure and returns its result as a boolean if the result is OkisErrAnd(callable $fn)- Executes the closure and returns its result as a boolean if the result is Err
-
map(callable $fn)- Transform the success valuemapErr(callable $fn)- Transform the error valueandThen(callable $fn)- Chain Result-returning operations
-
match(callable $okFn, callable $errFn)- Handle both success and error cases
-
inspect(callable $fn)- Inspect the success valueinspectErr(callable $fn)- Inspect the error value
-
unwrap()- Get the success value or throwunwrapErr()- Get the error value or throwunwrapOr(mixed $default)- Get the success value or a defaultunwrapOrElse(callable $fn)- Get the success value or compute a defaultunwrapOrDefault(DefaultValueProvider $provider)- Get the success value or type's defaultexpect(string $msg)- Get the success value or throw with custom messageexpectErr(string $msg)- Get the error value or throw with custom messageunwrapUnchecked()- Get the success value without checking (unsafe)unwrapErrUnchecked()- Get the error value without checking (unsafe)
Basic Usage
use Martyrer\Throwless\Ok; use Martyrer\Throwless\Err; use Martyrer\Throwless\Result; // Creating Results $success = new Ok(42); // Ok<int, mixed> $failure = new Err("something went wrong"); // Err<mixed, string> // Checking Result type $success->isOk(); // true $success->isErr(); // false $failure->isOk(); // false $failure->isErr(); // true // Unwrapping values $success->unwrap(); // 42 $failure->unwrapErr(); // "something went wrong" // Using default values $success->unwrapOr(0); // 42 $failure->unwrapOr(0); // 0
Core Methods
Type Checking
isOk
Check if the Result contains a success value:
$result = new Ok(42); $result->isOk(); // true $error = new Err("failed"); $error->isOk(); // false
isErr
Check if the Result contains an error value:
$result = new Ok(42); $result->isErr(); // false $error = new Err("failed"); $error->isErr(); // true
isOkAnd
Check if Result is Ok and the value matches a predicate:
$result = new Ok(42); $isEven = $result->isOkAnd(fn($x) => $x % 2 === 0); // true $isNegative = $result->isOkAnd(fn($x) => $x < 0); // false
isErrAnd
Check if Result is Err and the error matches a predicate:
$error = new Err("invalid input"); $isInputError = $error->isErrAnd(fn($e) => str_contains($e, "input")); // true $isTimeout = $error->isErrAnd(fn($e) => str_contains($e, "timeout")); // false
Transformation Methods
map
Transform the success value while preserving the error:
$result = new Ok(5); $doubled = $result->map(fn($x) => $x * 2); // Ok(10) $error = new Err("failed"); $doubled = $error->map(fn($x) => $x * 2); // Err("failed")
mapErr
Transform the error value while preserving the success:
$result = new Err("error"); $mapped = $result->mapErr(fn($e) => "Error: " . $e); // Err("Error: error") $success = new Ok(42); $mapped = $success->mapErr(fn($e) => "Error: " . $e); // Ok(42)
andThen
Chain operations that might fail:
function divide($x, $y): Result { return $y === 0 ? new Err("division by zero") : new Ok($x / $y); } $result = new Ok(10) ->andThen(fn($x) => divide($x, 2)) // Ok(5) ->andThen(fn($x) => divide($x, 0)); // Err("division by zero")
Matching
match
Handle both success and error cases:
$result = new Ok(42); $value = $result->match( fn($value) => "Success: $value", fn($error) => "Error: $error" ); // "Success: 42"
Inspection Methods
inspect
Perform side effects on success value without consuming the Result:
$result = new Ok(42); $result->inspect(fn($value) => print("Got value: $value")) ->map(fn($x) => $x * 2);
inspectErr
Perform side effects on error value without consuming the Result:
$error = new Err("error"); $error->inspectErr(fn($err) => print("Error occurred: $err")) ->mapErr(fn($err) => "Handled: $err");
Unwrapping Methods
unwrap
Get the success value or throw an exception:
$result = new Ok(42); $value = $result->unwrap(); // 42 $error = new Err("oops"); $value = $error->unwrap(); // throws UnwrapException
unwrapErr
Get the error value or throw an exception:
$error = new Err("error message"); $value = $error->unwrapErr(); // "error message" $success = new Ok(42); $value = $success->unwrapErr(); // throws UnwrapException
unwrapOr
Get the value or a default:
$result = new Err("error"); $value = $result->unwrapOr(42); // 42
unwrapOrElse
Get the value or compute a default:
$result = new Err("error"); $value = $result->unwrapOrElse(fn($error) => strlen($error)); // 5
unwrapOrDefault
Get the success value or the type's default value:
class DefaultProvider implements DefaultValueProvider { public function getDefault(): int { return 0; } } $result = new Err("error"); $value = $result->unwrapOrDefault(new DefaultProvider()); // 0
expect
Unwrap with a custom error message:
$result = new Ok(42); $value = $result->expect("This should never fail"); // 42 $error = new Err("oops"); $value = $error->expect("Critical error"); // throws UnwrapException with message "Critical error"
expectErr
Get the error value with a custom error message:
$error = new Err("not found"); $value = $error->expectErr("Expected error not found"); // "not found" $success = new Ok(42); $value = $success->expectErr("Expected an error"); // throws UnwrapException with message "Expected an error"
unwrapUnchecked
Get the success value without safety checks (use with caution):
// WARNING: Only use when you are absolutely certain the Result is Ok // Otherwise, it will cause undefined behavior $result = new Ok(42); $value = $result->unwrapUnchecked(); // 42
unwrapErrUnchecked
Get the error value without safety checks (use with caution):
// WARNING: Only use when you are absolutely certain the Result is Err // Otherwise, it will cause undefined behavior $error = new Err("error"); $value = $error->unwrapErrUnchecked(); // "error"
Real-world Examples
Example 1: User Authentication
class UserAuthenticator { public function authenticate(string $username, string $password): Result { $user = $this->findUser($username); if ($user === null) { return new Err("User not found"); } return password_verify($password, $user->password) ? new Ok($user) : new Err("Invalid password"); } } // Usage $auth = new UserAuthenticator(); $result = $auth->authenticate("john", "password123") ->map(fn($user) => $user->toArray()) ->mapErr(fn($error) => ["error" => $error]);
Example 2: API Response Handling
class ApiClient { public function fetchData(string $url): Result { try { $response = file_get_contents($url); $data = json_decode($response, true); return $data === null ? new Err("Invalid JSON response") : new Ok($data); } catch (Throwable $e) { return new Err($e->getMessage()); } } } // Usage $client = new ApiClient(); $result = $client->fetchData("https://api.example.com/data") ->andThen(function($data) { return isset($data['items']) ? new Ok($data['items']) : new Err("Missing items in response"); }) ->map(fn($items) => array_map(fn($item) => $item['name'], $items));
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. Make sure to read the contributing guidelines before submitting your PR.
License
This project is licensed under the MIT License - see the LICENSE file for details.
martyrer/throwless-php 适用场景与选型建议
martyrer/throwless-php 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 2 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 04 月 19 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「php」 「exceptions」 「functional」 「monad」 「error-handling」 「result」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 martyrer/throwless-php 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 martyrer/throwless-php 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 martyrer/throwless-php 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
php7ify is a project that brings new php7 classes and exceptions to php 5.x.
Connection 'Db' codeception module to 'Yii2' module database settings
The CodenamePHP Platform core that contains basic interfaces, exceptions etc..
Functional library for php with proper currying
Iteration tools for PHP
A simple package to better handle Exceptions.
统计信息
- 总下载量: 2
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 25
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-04-19