PHPackages                             joe.szeto/capsule - 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. joe.szeto/capsule

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

joe.szeto/capsule
=================

v0.1.5(9mo ago)05.8k↓50%PHP

Since Jul 18Pushed 9mo ago1 watchersCompare

[ Source](https://github.com/joeszetocodeman/capsule)[ Packagist](https://packagist.org/packages/joe.szeto/capsule)[ RSS](/packages/joeszeto-capsule/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (2)Versions (16)Used By (0)

Install
-------

[](#install)

```
composer require joe.szeto/capsule

```

Basic usage
-----------

[](#basic-usage)

we can use attribute `Setter` to tell the code the following Closure is a setter, and the value of the setter is the return value of the closure

```
$me = capsule(
    #[Setter('name')]
    fn() => 'szeto',
    #[Setter('age')]
    fn() => 30,
    #[Setter('sex')]
    fn() => 'man'
)->thenReturn(fn(string $name, int $age, string $sex) => [ $name, $age, $sex ]);
// to be ['szeto', 30, 'man']
```

we can also use method `set` to set the value of the setter

```
$me = capsule()
    ->set('name', fn() => 'szeto')
    ->set('age', fn() => 30)
    ->set('sex', fn() => 'man')
    ->thenReturn(fn(string $name, int $age, string $sex) => [ $name, $age, $sex ]);
// to be ['szeto', 30, 'man']
```

Auto resolve params
-------------------

[](#auto-resolve-params)

if the closure has type hints and the type hint is the same as the value of the setter, the value will be resolved automatically even if the params name is not 100% match, it will still work

```
$name = capsule()
    ->set('name', 'szeto')
    ->thenReturn(fn(string $myName) => $myName);
```

we can resolve parameters by the application container leverages the underlying container's reflection capabilities. This means that when a closure or callable object is executed, the Capsule library can automatically inject the required dependencies as defined by the type hints of the parameters.

```
capsule()
    ->thenReturn(fn(WhenEmpty $empty) => expect($empty)->toBeInstanceOf(WhenEmpty::class));
```

OnBlank
-------

[](#onblank)

it will only call when the value of the setter is null

```
$name = capsule()
    ->set('name', fn() => null)
    ->through(
        #[OnBlank('name'), Setter('name')]
        fn() => 'szeto' // this closure only call when the value of 'name' is null
    )->thenReturn('name');
```

we can also use attribute `SetOnBlank` to set and detect the OnBlank at the same time

```
 $name = capsule()
        ->set('name', fn() => null)
        ->through(
            #[SetOnBlank('name')]
            fn() => 'szeto'
        )
        ->thenReturn('name');
```

we can also use method `setOnBlank` to set the OnBlank

```
$name = capsule()
    ->set('name', fn() => null)
    ->setOnBlank('name', fn() => 'szeto')
    ->thenReturn('name');
```

### Closure

[](#closure)

if the set value is a closure, when the type hint of the param of using is Closure the original closure will be passed to the param

```
    $name = capsule()
        ->set('name', fn() => 'szeto')
        ->thenReturn(fn(Closure $name) => $name());
    expect($name)->toBe('szeto');
```

when the type hint of the params is a NOT closure, the value will be return

```
    $name = capsule()
        ->set('name', fn() => 'szeto')
        ->thenReturn(
            fn(string $name) => $name // now name is szeto, not a closure
        );
    expect($name)->toBe('szeto');
```

### Evaluable

[](#evaluable)

if the type is closure, and call it we have to pass the params manually

```
    $name = capsule()
        ->set('prefix', fn() => 'Joe')
        ->set('name', fn(string $prefix) => $prefix. ' szeto')
        ->thenReturn(
            fn(Closure $name, string $prefix) => $name($prefix) // params is Joe
        );
```

but if we pass the param one by one manually it will be very tedious now Evaluable become handy

```
capsule()
    ->set('prefix', fn() => 'Joe')
    ->set('name', fn(string $prefix) => $prefix. ' szeto')
    ->thenReturn(
        fn(Evaluable $name) => $name() // params is Joe
    );
```

### Each

[](#each)

for each value, the closure will be called

```
$names = capsule()
    ->set('names', fn() => ['szeto', 'joe'])
    ->through(
        #[Each('names' as: 'name')]
        fn(string $name) => $name // 'szeto', 'joe'
    )->run();
```

### Only

[](#only)

```
capsule()
    ->through(
        fn() => throw new Exception('should not run'),
        #[Only]
        fn() => expect(true)->toBeTrue()
    )
    ->run();
```

### Skip

[](#skip)

```
capsule()
    ->through(
        fn() => expect(true)->toBeTrue(),
        #[Skip]
        fn() => throw new Exception('should not run'),
    )
    ->run();
```

### Mocking

[](#mocking)

The Capsule::mock method allows developers to replace parts of their application's behavior with predetermined responses or operations. This is particularly useful in testing, where you want to isolate the part of the application you are testing and control its interactions with external dependencies.

```
public static function mock(string $key, mixed $value): void
```

To replace a string value within the capsule, simply pass the key and the new string value to the mock method.

```
Capsule::mock('name', 'szeto');
```

If you need to mock the behavior of a function, provide a closure as the second argument. This closure will be executed in place of the original function associated with the given key.

```
Capsule::mock('name', fn() => 'szeto');
```

To mock an object, pass an instance of the class as the second argument. This instance will replace any existing instances bound to the specified key within the capsule.

```
Capsule::mock('name', new OnBlank('szeto'));
```

Mock with sequence

```
Capsule::mock(OnBlank::class, new Sequence(
    new OnBlank('szeto'), new OnBlank('joe')
));
capsule()
    ->through(
        fn(OnBlank $name) => expect($name->getKey())->toBe('szeto'),
        fn(OnBlank $name) => expect($name->getKey())->toBe('joe')
    )->run();
```

### Catch

[](#catch)

```
    capsule(
        fn() => throw new Exception('foo'),
        #[Cat(Exception::class)]
        fn($message) => expect($message)->toBe('foo')
    )->run();
```

### Namespace

[](#namespace)

it can resolve params from namespace, capsules under same namespace can share the value

```
    capsule()
        ->namespace('some:namespace')
        ->set('name', 'szeto')->run();

    capsule()
        ->namespace('some:namespace')
        ->through(
            fn(string $name) => expect($name)->toBe('szeto')
        )->run();
```

### Append

[](#append)

append function will append the callable to the end of the capsule

```
    $capsule = capsule()->through(
        #[Setter('name')]
        fn() => 'szeto'
    );

    $name = $capsule->append(
        #[Setter('name')]
        fn($name) => 'joe ' . $name
    )->thenReturn('name');

    expect($name)->toBe('joe szeto');
```

use append combined with namespace

```
    capsule()->namespace('abc:foo')->append(
        #[Setter('name')]
        fn(string $name) => 'joe ' . $name
    );

    $name = capsule()
        ->namespace('abc:foo')
        ->through(
            #[Setter('name')]
            fn() => 'szeto'
        )->thenReturn('name');

    // now name is joe szeto
```

### massage

[](#massage)

when we want to change the value of some variable we will always do something like the following

```
return capsule()
    ->namespace($namespace)
    ->set($data)
    ->thenReturn($return);
```

so I come up with the idea of massage

```
return massage($namespace, $data, $return);
```

or

```
return massage($namespace, $data);
```

but if we want to use this approach, we have to follow some conventions

`$namespace` = `someClassname:someFunction:someVariableName`

and the `someVariableName` must be the key of the data

for example

```
massage(Foo::class.':handle:name', ['name' => 'szeto']);
```

this is equivalent to

```
capsule()
    ->namespace(Foo::class.':handle:name')
    ->set('name', 'szeto')
    ->thenReturn('name');
```

###  Health Score

33

—

LowBetter than 75% of packages

Maintenance56

Moderate activity, may be stable

Popularity23

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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 ~26 days

Recently: every ~74 days

Total

15

Last Release

292d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8236606e09aee05405be84a246f7471ed6af5390b3cbb8d8852ea21e167d990a?d=identicon)[jokersk](/maintainers/jokersk)

---

Top Contributors

[![joeszetocodeman](https://avatars.githubusercontent.com/u/5194890?v=4)](https://github.com/joeszetocodeman "joeszetocodeman (51 commits)")

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/joeszeto-capsule/health.svg)

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

###  Alternatives

[wireui/wireui

TallStack components

1.8k1.3M16](/packages/wireui-wireui)[livewire/volt

An elegantly crafted functional API for Laravel Livewire.

4195.3M84](/packages/livewire-volt)[ramonrietdijk/livewire-tables

Dynamic tables for models with Laravel Livewire

21147.4k](/packages/ramonrietdijk-livewire-tables)

PHPackages © 2026

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