PHPackages                             tetthys/wrap - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. tetthys/wrap

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

tetthys/wrap
============

Minimal Result-like wrapper with fluent map/filter/reduce and conditional helpers for PHP 8.3+.

0.1.3(4mo ago)158MITPHPPHP ^8.4

Since Oct 17Pushed 4mo agoCompare

[ Source](https://github.com/tetthys/wrap)[ Packagist](https://packagist.org/packages/tetthys/wrap)[ RSS](/packages/tetthys-wrap/feed)WikiDiscussions dev Synced 1mo ago

READMEChangelog (10)Dependencies (1)Versions (14)Used By (0)

Wrap
====

[](#wrap)

A minimal, fluent **Result-like wrapper** for PHP 8.3+.

- Safely execute code and keep either a value (**ok**) or a captured exception (**fail**)
- Transform values (`then`, `map`, `filter`, `reduce`)
- Use expressive flow helpers (`when`, `unless`, `branch`)
- Add modern chain helpers (`andThen`, `ensure`, `recoverWhen`, `mapError`, `rethrowWhen`, `tap`, `tryTap`, `failWhen`)
- Support optional pipelines (`keep`, `whenValue`, `whenValueThen`) and error side-effects (`tapError`, `tryTapError`)
- **Make exception behavior explicit** with `safe*`, `try*`, and `rethrow*` helpers

---

Installation
------------

[](#installation)

```
composer require tetthys/wrap
```

---

Quick Start
-----------

[](#quick-start)

```
use Tetthys\Wrap\Wrap;

$result = Wrap::handle(fn() => riskyOperation())
    ->tryOk(fn($v) => logger()->info('ok', ['value' => $v]))       // swallows callback exceptions
    ->tryFail(fn($e) => logger()->warning('fail', ['msg' => $e->getMessage()])) // swallows callback exceptions
    ->rescue(fn() => 42)                                          // recover from failure
    ->then(fn($v) => $v * 2)
    ->getValueOr(0);

echo $result; // 84
```

---

Exception Policy (Important)
----------------------------

[](#exception-policy-important)

Wrap deliberately separates **how exceptions are handled** by method name. You should be able to tell whether an exception is **thrown**, **captured**, or **swallowed** just by reading the chain.

### 1) **Thrown (escape the Wrap boundary)**

[](#1-thrown-escape-the-wrap-boundary)

These methods **do not catch** exceptions from callbacks or explicitly rethrow errors:

- `then`, `map`, `filter`, `reduce`
- `ok`, `fail`
- `rethrowWhen`
- `rescueWhen` (when predicate does not match)
- `rescueExcept` (when error matches except list)
- `throwIfFailed`, `rethrow`, `rethrowRoot`

Use these when an error **must propagate** to the caller.

---

### 2) **Captured (invalidate the chain)**

[](#2-captured-invalidate-the-chain)

These methods **catch exceptions and convert them into a failed Wrap state**(using `InvalidArgumentException` with the original error as `previous`):

- `safeThen`, `safeMap`, `safeFilter`, `safeReduce`
- `tap`, `tapError`
- `when`, `unless`, `branch`
- `ensure`, `safeKeep`
- `whenValue`, `whenValueThen`
- **Added:** `safeOk`, `safeFail`

Use these when errors should stay **inside** the Wrap pipeline.

---

### 3) **Swallowed (ignored)**

[](#3-swallowed-ignored)

These methods **ignore callback exceptions entirely** and keep the current state:

- `tryTap`, `tryTapError`
- **Added:** `tryOk`, `tryFail`

Use these for logging, metrics, tracing, or any side effects that must **never break the flow**.

---

### Recommended rule of thumb

[](#recommended-rule-of-thumb)

- Logging / metrics / monitoring → `try*`
- Business logic that may fail → `safe*`
- Domain or application boundaries → `throwIfFailed` / `rethrow*`

---

Construction
------------

[](#construction)

### `Wrap::handle(callable $callback)`

[](#wraphandlecallable-callback)

Runs a callback and captures its return value or any thrown `Throwable`.

```
$wrap = Wrap::handle(fn() => 42);
$wrap = Wrap::handle(fn() => throw new RuntimeException('boom'));
```

### `Wrap::fromValue(mixed $value)`

[](#wrapfromvaluemixed-value)

Creates a successful Wrap.

```
$wrap = Wrap::fromValue(['a' => 1]);
```

### `Wrap::fromError(Throwable $error)`

[](#wrapfromerrorthrowable-error)

Creates a failed Wrap.

```
$wrap = Wrap::fromError(new RuntimeException('x'));
```

---

Side Effects
------------

[](#side-effects)

### `ok(callable $callback)` / `fail(callable $callback)`

[](#okcallable-callback--failcallable-callback)

Runs only on success / failure.

⚠ **If the callback throws, the exception is thrown immediately.**

```
Wrap::handle(fn() => 10)
    ->ok(fn($v) => logger()->info("Value: $v"));
```

---

### `safeOk(callable $callback)` / `safeFail(callable $callback)` ✅

[](#safeokcallable-callback--safefailcallable-callback-)

Runs only on success / failure.

If the callback throws, the chain is **invalidated**.

```
Wrap::handle(fn() => 10)
    ->safeOk(fn($v) => riskyLog($v))
    ->then(fn($v) => $v + 1);
```

---

### `tryOk(callable $callback)` / `tryFail(callable $callback)` ✅

[](#tryokcallable-callback--tryfailcallable-callback-)

Runs only on success / failure.

If the callback throws, the exception is **swallowed**.

```
Wrap::handle(fn() => 10)
    ->tryOk(fn($v) => riskyLog($v))
    ->then(fn($v) => $v + 1);
```

---

### `always(callable $callback): void`

[](#alwayscallable-callback-void)

Always runs (finally-style) and **ends the chain**.

Receives `(bool $ok, ?Throwable $error, mixed $value)`.

---

### `finally(callable $callback)`

[](#finallycallable-callback)

Always runs and continues the chain. If the callback throws, the chain is invalidated.

---

Transformations
---------------

[](#transformations)

### `then(callable $callback)`

[](#thencallable-callback)

Transforms the stored value on success.

⚠ If the callback throws, the exception is **thrown**.

```
$out = Wrap::handle(fn() => 10)
    ->then(fn(int $x) => $x + 5)
    ->then(fn(int $x) => (string) ($x * 2))
    ->getValueOr('fallback');
```

### `safeThen(callable $callback)`

[](#safethencallable-callback)

Catches exceptions and invalidates instead of throwing.

---

Iterable Operators
------------------

[](#iterable-operators)

`map`, `filter`, and `reduce` require the stored value to be `iterable`.

- `map` / `filter` / `reduce` → **throw**
- `safeMap` / `safeFilter` / `safeReduce` → **invalidate**

---

Recovery
--------

[](#recovery)

### `rescue(callable $fallback)`

[](#rescuecallable-fallback)

On failure, provides a fallback value and flips the state to success.

✅ The fallback may accept **zero arguments** or **one `Throwable` argument**.

```
Wrap::handle(fn() => throw new RuntimeException('oops'))
    ->rescue(fn() => 123)
    ->getValueOr(-1);
```

```
Wrap::handle(fn() => throw new RuntimeException('oops'))
    ->rescue(fn(Throwable $e) => 123);
```

---

### `recoverWhen(string|callable $matcher, callable $fallback)`

[](#recoverwhenstringcallable-matcher-callable-fallback)

Recover **only when** the failure matches a class-string or predicate.

---

Flat-mapping
------------

[](#flat-mapping)

### `andThen(callable $callbackReturningWrap)`

[](#andthencallable-callbackreturningwrap)

Like `then()`, but flattens another `Wrap` into the chain.

---

Validation
----------

[](#validation)

### `ensure(callable $predicate, string|callable $message = 'Ensure failed')`

[](#ensurecallable-predicate-stringcallable-message--ensure-failed)

Invalidates the chain when the predicate returns `false`.

---

Optional Value Flow
-------------------

[](#optional-value-flow)

Helpers for pipelines where `null` means “no work to do”:

- `keep`, `safeKeep`
- `whenValue`, `whenValueThen`

---

Error Utilities
---------------

[](#error-utilities)

### `throwIfFailed(?callable $factory = null)` ✅

[](#throwiffailedcallable-factory--null-)

Escapes the Wrap boundary. Throws the captured error if failed.

---

### `rethrow()` ✅

[](#rethrow-)

Throws the captured error as-is. If invalidated, throws the wrapper exception.

---

### `rethrowRoot()` ✅

[](#rethrowroot-)

Throws the **root cause** error (the `previous` exception when wrapped).

```
Wrap::handle(fn() => 1)
    ->safeThen(fn() => throw new RuntimeException('root'))
    ->rethrowRoot();
```

---

### `rethrowWhen(string|callable $matcher)`

[](#rethrowwhenstringcallable-matcher)

Throws the captured error only when it matches.

---

### `tapError` / `tryTapError`

[](#taperror--trytaperror)

- `tapError` → callback throws → invalidate
- `tryTapError` → callback throws → swallow

---

Extraction &amp; Accessors
--------------------------

[](#extraction--accessors)

- `isOk()`
- `getError()`
- `getValue()`
- `getValueOr()`
- `getValueOrCall()`
- `getValueOrNull()`
- `getOrThrow()`

---

Optional Global Helper
----------------------

[](#optional-global-helper)

```
function wrap(callable $callback): Wrap
{
    return Wrap::handle($callback);
}
```

---

License
-------

[](#license)

MIT

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance75

Regular maintenance activity

Popularity10

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~6 days

Total

13

Last Release

136d ago

PHP version history (2 changes)0.0.1PHP ^8.3

0.0.8PHP ^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/858f92afec0ff81e6888c9ae6f363b56ebf82e45a32d9e1b37341569c5d1b267?d=identicon)[tetthys](/maintainers/tetthys)

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/tetthys-wrap/health.svg)

```
[![Health](https://phpackages.com/badges/tetthys-wrap/health.svg)](https://phpackages.com/packages/tetthys-wrap)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
