PHPackages                             jclaveau/php-deferred-callchain - 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. [Queues &amp; Workers](/categories/queues)
4. /
5. jclaveau/php-deferred-callchain

ActiveLibrary[Queues &amp; Workers](/categories/queues)

jclaveau/php-deferred-callchain
===============================

Register a chain of calls that will be applied on an instance later

1.5.0(2mo ago)17.0k↓100%[3 issues](https://github.com/jclaveau/php-deferred-callchain/issues)MITPHPPHP ^8.0CI failing

Since Nov 6Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/jclaveau/php-deferred-callchain)[ Packagist](https://packagist.org/packages/jclaveau/php-deferred-callchain)[ RSS](/packages/jclaveau-php-deferred-callchain/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (3)Versions (18)Used By (0)

PHP Deferred Callchain
======================

[](#php-deferred-callchain)

This class simply provides a way to define fluent chain of methods, functions, array access calls before having the target (object or native value) you wan't to apply it to. Once the expected targets are available, simply call the chain on them as if it was a function.

[![Latest Stable Version](https://camo.githubusercontent.com/fe55eda4e3092d5bdb229ec8c1d0507d343202b3730f966d084c950bb5471ea5/68747470733a2f2f706f7365722e707567782e6f72672f6a636c61766561752f7068702d64656665727265642d63616c6c636861696e2f762f737461626c65)](https://packagist.org/packages/jclaveau/php-deferred-callchain)[![License](https://camo.githubusercontent.com/f54a68d1a38a2ce05a9716f0efc554eae2818680405b1767245ccd7cef2a3576/68747470733a2f2f706f7365722e707567782e6f72672f6a636c61766561752f7068702d64656665727265642d63616c6c636861696e2f6c6963656e7365)](https://packagist.org/packages/jclaveau/php-deferred-callchain)[![Total Downloads](https://camo.githubusercontent.com/6d110b018042d566258a4009529fe2046b5d5b2455ed781a37e64a8d9f42ea7f/68747470733a2f2f706f7365722e707567782e6f72672f6a636c61766561752f7068702d64656665727265642d63616c6c636861696e2f646f776e6c6f616473)](https://packagist.org/packages/jclaveau/php-deferred-callchain)[![contributions welcome](https://camo.githubusercontent.com/9e93e892d0685e1bf7a1d0bd7c8410d6ecf2086a0a7b48dd58a6b96fa556ea2a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6e747269627574696f6e732d77656c636f6d652d627269676874677265656e2e7376673f7374796c653d666c6174)](https://github.com/jclaveau/php-deferred-callchain/issues)

Quality
-------

[](#quality)

[![Tests](https://github.com/jclaveau/php-deferred-callchain/actions/workflows/tests.yml/badge.svg)](https://github.com/jclaveau/php-deferred-callchain/actions/workflows/tests.yml)[![codecov](https://camo.githubusercontent.com/830c1ef9cc0a4f7076988c2fe65c3c4ad4c14d5d3800fa1d818c5110e3bd36ba/68747470733a2f2f636f6465636f762e696f2f67682f6a636c61766561752f7068702d64656665727265642d63616c6c636861696e2f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/jclaveau/php-deferred-callchain)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/27c738da692d3cf78bf3453b8a238001dec7492c5bce31a62640f04b2aed793d/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a636c61766561752f7068702d64656665727265642d63616c6c636861696e2f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/jclaveau/php-deferred-callchain/?branch=master)

Overview
--------

[](#overview)

```
// having
class MyClass
{
    protected $name = 'unnamed';

    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    public function nameEntries()
    {
        return [
            'my_entry_1' => $this->name . " 1",
            'my_entry_2' => $this->name . " 2",
        ];
    }
}

// We can define some chained calls (none is executed)
$doDummyCallsLater = DeferredCallChain::new_( MyClass::class )  // Targets must be MyClass instances
    ->nameEntries()['my_entry_2']                               // access array entry
    ->strtoupper()                                              // apply strtoupper() to it
    ;

// do whatever we want
// ...

// Get your targets
$myInstance1 = (new MyClass)->setName('foo');
$myInstance2 = (new MyClass)->setName('bar');

// Execute the callchain
echo $doDummyCallsLater( $myInstance1 ); // => FOO 2
echo $doDummyCallsLater( $myInstance2 ); // => BAR 2
```

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

[](#installation)

php-deferred-callchain is installable via [Composer](http://getcomposer.org)

```
composer require jclaveau/php-deferred-callchain

```

Testing
-------

[](#testing)

Tests are located [here](tests/unit/DeferredCallChainTest.php) and runnable by calling

```
./phpunit

```

Usage
-----

[](#usage)

- [Functionnal and chained construction](#functionnal-and-chained-construction)
- [Fluent call chain](#fluent-call-chain)
- [Working with arrays](#working-with-arrays)
- [Working with native types and functions](#working-with-native-types-and-functions)
- [Specifying on which class, interface, type or instance, the chain is callable](#specifying-on-which-class-interface-type-or-instance-the-chain-is-callable)
- [Calls provoking exceptions](#calls-provoking-exceptions)
- [Static calls](#static-calls)
- [API Reference](api_reference)

### Functionnal and chained construction

[](#functionnal-and-chained-construction)

DeferredCallChain can be instanciated classically

```
$nameRobert = (new DeferredCallChain(Human::class))->...
```

Statically

```
$nameRobert = DeferredCallChain::new_(Human::class)->...
```

Or functionnaly

```
$nameRobert = later(Human::class)->...
```

### Fluent call chain

[](#fluent-call-chain)

```
$nameRobert = DeferredCallChain::new_()
    ->setName('Muda')
    ->setFirstName('Robert')
    ;

$mySubjectIMissedBefore = new Human;
$robert = $nameRobert( $mySubjectIMissedBefore );

echo $robert->getFullName(); // => "Robert Muda"
echo (string) $nameRobert;   // => "(new JClaveau\Async\DeferredCallChain)->setName('Muda')->setFirstName('Robert')"
```

### Working with arrays

[](#working-with-arrays)

```
$getSubColumnValue = DeferredCallChain::new_()
    ['column_1']
    ['sub_column_3']
    ;

$sub_column_3_value = $getSubColumnValue( [
    'column_1' => [
        'sub_column_1' => 'lalala',
        'sub_column_2' => 'lololo',
        'sub_column_3' => 'lilili',
    ],
    'column_2' => [
        'sub_column_1' => 'lululu',
        'sub_column_2' => 'lelele',
        'sub_column_3' => 'lylyly',
    ],
] );

echo $sub_column_3_value;           // => "lilili"
echo (string) $getSubColumnValue;   // => "(new JClaveau\Async\DeferredCallChain)['column_1']['sub_column_3']"
```

### Working with native types and functions

[](#working-with-native-types-and-functions)

The features above make calls to objects methods easy and async but when their result is not an object, the fluent syntax has to stop, and the async behavior also.

Based on Daniel S Deboer work , support of chained function calls has been added.

```
class MyClass
{
    public function getString()
    {
        return 'string';
    }
}

$upperifyMyClassString = DeferredCallChain::new_( MyClass::class )
    ->getString()
    ->strtoupper();

echo $upperifyMyClassString( new MyClass ); // prints "STRING"
```

Some functions do not use the subject of the fluent syntax as first argument. In this case, giving '$$' as the parameter you want to be replaced by the subject.

```
class MyClass
{
    public function getSentence()
    {
        return 'such a funny lib to implement';
    }
}

$explodeMyClassSentence = DeferredCallChain::new_( MyClass::class )
    ->getSentence()
    ->explode(' ', '$$');

$explodeMyClassSentence( new MyClass ); // returns ['such', 'a', 'funny', 'lib', 'to', 'implement']
```

### Specifying on which class, interface, type or instance, the chain is callable

[](#specifying-on-which-class-interface-type-or-instance-the-chain-is-callable)

You can force the target of your call chain to:

- be an instance of a specific class

```
$nameRobert = DeferredCallChain::new_(Alien::class)
    ->setName('Muda')
    ->setFirstName('Robert')
    ;

$mySubjectIMissedBefore = new Human;
$robert = $nameRobert( $mySubjectIMissedBefore );

// throws BadTargetClassException
```

- implement a specific interface

```
$getCount = DeferredCallChain::new_("\Traversable")
    ->count()
    ;

$myCountableIMissedBefore = new CountableClass; // class implementing Countable

// throws BadTargetInterfaceException
```

- be of a specific native type

```
$nameRobert = DeferredCallChain::new_("array")
    ->setName('Muda')
    ->setFirstName('Robert')
    ;

$mySubjectIMissedBefore = new Human;
$robert = $nameRobert( $mySubjectIMissedBefore );

// throws BadTargetTypeException
```

- be a specific instance given at construction

```
$myTarget = new Human;
$nameRobert = DeferredCallChain::new_($myTarget)
    ->setName('Muda')
    ->setFirstName('Robert')
    ;

$robert = $nameRobert( new Human );

// throws TargetAlreadyDefinedException
```

### Calls provoking exceptions

[](#calls-provoking-exceptions)

As a call can be made far before it's effectivelly applied, exceptions need more debug information for a smooth workflow. To achieve that, a line is added to every exception message thrown during a DeferredCallChain execution, pointing to the buggy call and where it is coded.

For example, an exception having as message `An exception has been thrown by some user code`will print

```
An exception has been thrown by some user code
When applying (new JClaveau\Async\DeferredCallChain(  ))->previousSuccessfullCall()->buggyCall('Robert') defined at :

```

### Static calls

[](#static-calls)

Static calls can be useful, especially for singletons. For some technical reasons explained [here](https://github.com/jclaveau/php-deferred-callchain/issues/9), the only way to support it is to call them as normal methods (e.g. with -&gt; ) and look for it as a static method once we know it doesn't exist as a regular one.

```
later(MyModel::class)->getInstance()->myNormalGetter();
// or
later($myModel)->getInstance()->myNormalGetter(); // like $myModel::getInstance()
```

###  Health Score

46

—

FairBetter than 93% of packages

Maintenance66

Regular maintenance activity

Popularity20

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity75

Established project with proven stability

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

Recently: every ~577 days

Total

15

Last Release

66d ago

PHP version history (2 changes)1.0.0PHP &gt;=5.6.0

1.5.0PHP ^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/cc5884f6e6eb1ed07e687cfbb421981d94dd9133e85220df1a546c7f78851bd7?d=identicon)[jclaveau](/maintainers/jclaveau)

---

Top Contributors

[![jclaveau](https://avatars.githubusercontent.com/u/1556489?v=4)](https://github.com/jclaveau "jclaveau (44 commits)")

---

Tags

asynccall-chaindeferredfluentlaterlazyphp5php7phpasynchronouspromisefluentfuturelazyPHP7php8Chaincallslater

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jclaveau-php-deferred-callchain/health.svg)

```
[![Health](https://phpackages.com/badges/jclaveau-php-deferred-callchain/health.svg)](https://phpackages.com/packages/jclaveau-php-deferred-callchain)
```

###  Alternatives

[amphp/amp

A non-blocking concurrency framework for PHP applications.

4.4k123.4M322](/packages/amphp-amp)[icicleio/icicle

Icicle is a PHP library for writing asynchronous code using synchronous coding techniques.

1.1k150.9k14](/packages/icicleio-icicle)[recoil/react

Integrate Recoil with ReactPHP.

32274.4k12](/packages/recoil-react)[claudsonm/cep-promise-php

Busca por CEP utilizando Promises nos serviços dos Correios, ViaCEP, CepAberto e outros.

3120.0k](/packages/claudsonm-cep-promise-php)[async-interop/promise

A promise interface for interoperability in async operations.

652.5k1](/packages/async-interop-promise)

PHPackages © 2026

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