PHPackages                             sanmai/later - 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. sanmai/later

ActiveLibrary

sanmai/later
============

Later: deferred wrapper object

0.1.7(1y ago)7222.6M—1.4%3[1 issues](https://github.com/sanmai/later/issues)7Apache-2.0PHPPHP &gt;=8.2CI passing

Since Mar 15Pushed 5mo ago2 watchersCompare

[ Source](https://github.com/sanmai/later)[ Packagist](https://packagist.org/packages/sanmai/later)[ GitHub Sponsors](https://github.com/sanmai)[ RSS](/packages/sanmai-later/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (8)Dependencies (8)Versions (9)Used By (7)

[![Latest Stable Version](https://camo.githubusercontent.com/cf1779c2c6996682dec9577186f2bb2f2c9fc743556b62c7a12020ead5475a45/68747470733a2f2f706f7365722e707567782e6f72672f73616e6d61692f6c617465722f762f737461626c65)](https://packagist.org/packages/sanmai/later)[![CI](https://github.com/sanmai/later/workflows/CI/badge.svg)](https://github.com/sanmai/later/workflows/CI/badge.svg)[![Coverage Status](https://camo.githubusercontent.com/1b05df38782d633d15705d8f5d67176cca9833434dcaf59e6d9c5f3201b73e39/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f73616e6d61692f6c617465722f62616467652e7376673f6272616e63683d6d61696e)](https://coveralls.io/github/sanmai/later?branch=main)[![Type Coverage](https://camo.githubusercontent.com/75b683e9ada6295a8b94be17cf0439d722dd4d85fef8ac18fae01b83c4089052/68747470733a2f2f73686570686572642e6465762f6769746875622f73616e6d61692f6c617465722f636f7665726167652e737667)](https://shepherd.dev/github/sanmai/later)

This rigorously tested fully-typed library just works. It neither defines nor throws any exceptions.

Install
=======

[](#install)

```
composer require sanmai/later

```

The latest version requires PHP 7.4 or greater.

Use
===

[](#use)

To use this pattern you need a generator function, yielding a single item of type you want to produce lazily. Pass it to `later()`, a static wrapper returning a `Deferred` object:

For example:

```
use function Later\later;

$deferred = later(function () {
    $deepThought = new DeepThought();
    $deepThought->solveTheQuestion();

    yield $deepThought;
});
```

And then call `get()` when needed, as many times as needed:

```
$deferred->get()->getAnswer(); // 42
$deferred->get()->getAnswer(); // same 42
```

Using a generator instead of a traditional callback comes with a major benefit: any generator is guaranteed by the language to be used exactly once. You can be sure that it won't be called twice.

But that's not all: read on.

No Callbacks Required
---------------------

[](#no-callbacks-required)

Making a closure generator on the spot isn't always convenient. And not to say these closures are much different from all-too-familiar callbacks. Not at all different from the looks of them.

The power of this pattern is in its ability to make use of any function, previously returning a single value, without any need for any additional callbacks or closures.

Consider this diff:

```
 private function makeFooBar()
 {
    //...

-    return $foo;
+    yield $foo;
 }
```

After adding `Later\lazy` to the mix:

```
 use function Later\lazy;

 public function __construct()
 {
-    $this->fooBar = $this->makeFooBar();
+    $this->lazyFooBar = lazy($this->makeFooBar());
 }

 public function usesFooBar()
 {
     if ($fooBarReallyRequired) {
-        $this->fooBar->getResult();
+        $this->lazyFooBar->get()->getResult();
     }
 }
```

We can see, this simple, single-line, change in the original method freed our program from creating things it may not need, postponing this process until the last moment, while also avoiding any use of callbacks.

Type Transparency
-----------------

[](#type-transparency)

The library is completely typed. [PHPStan](https://github.com/phpstan/phpstan), [Psalm](https://github.com/vimeo/psalm), and [Phan](https://github.com/phan/phan) are all routinely supported.

To use this capability it is recommended to declare a variable holding this object as `\Later\Interfaces\Deferred`.

In this example it will be `Deferred`:

```
use Later\Interfaces\Deferred;
use function Later\lazy;

final class HyperIntelligentMice
{
    /** @var Deferred */
    private $supercomputer;

    public function __construct(DeepThought $deepThought)
    {
        $this->supercomputer = lazy(self::updateDeepThought($deepThought));
    }

    /** @return iterable */
    private static function updateDeepThought(DeepThought $deepThought): iterable
    {
        $deepThought->solveTheQuestion();

        yield $deepThought;
    }

    public function getAnswer(): int
    {
        return $this->supercomputer->get()->getAnswer();
    }
}
```

Following this approach, a static analyzer or IDE will be able to understand what is called, and what is returned.

### Proxy Syntax

[](#proxy-syntax)

The library supports convenient proxy syntax for accessing methods and properties directly from the deferred object:

```
/** @var \Later\Interfaces\Deferred $deferred */
$deferred->getAnswer(); // 42
$deferred->answer;      // 42
```

With the explicit type IDEs such as PhpStorm can autocomplete proxied members.

Eager Execution
---------------

[](#eager-execution)

What if a program calls for `Deferred` object, but lazy evaluation is not required? For example, because a result is already available being loaded from a cache.

No problem, there's a function for this:

```
use function Later\now;

$deferred = now($result);
$deferred->get(); // returns $result
```

This deferred-but-not-deferred object implements the same interface, and can be used anywhere where a normal `Deferred` object would go.

Writing Tests
=============

[](#writing-tests)

The underlying `Deferred` object is fairly lax about input types. It will be happy to accept any `iterable`, not just generators.

This makes it super easy to use in mocks:

```
use function Later\lazy;

$this->lazyDependency = lazy([
    $myDependency,
]);
```

Yet for constant and already-known answers best to use a non-deferred variant:

```
use function Later\now;

$this->lazyDependency = now($myDependency);
```

And that's it. No need to go through loops assembling closures and whatnot.

If nothing else, one can make a common mock for it:

```
$deferredMock = $this->createMock(\Later\Interfaces\Deferred::class);
$deferredMock
    ->expects($this->once())
    ->method('get')
    ->willReturn($myDependency)
;
```

API Overview
============

[](#api-overview)

MethodTakesReturns`Later\lazy()``iterable``\Later\Interfaces\Deferred``Later\later()`A generator callback for `T``\Later\Interfaces\Deferred``Later\now()``T``\Later\Interfaces\Deferred`

###  Health Score

56

—

FairBetter than 98% of packages

Maintenance62

Regular maintenance activity

Popularity61

Solid adoption and visibility

Community22

Small or concentrated contributor base

Maturity64

Established project with proven stability

 Bus Factor1

Top contributor holds 88.2% 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 ~269 days

Recently: every ~141 days

Total

8

Last Release

373d ago

PHP version history (5 changes)0.1PHP ^7.1

0.1.1PHP ^7.1 || ^8.0

0.1.2PHP &gt;=7.1

0.1.3PHP &gt;=7.4

0.1.6PHP &gt;=8.2

### Community

Maintainers

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

---

Top Contributors

[![sanmai](https://avatars.githubusercontent.com/u/139488?v=4)](https://github.com/sanmai "sanmai (60 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")[![szepeviktor](https://avatars.githubusercontent.com/u/952007?v=4)](https://github.com/szepeviktor "szepeviktor (3 commits)")[![Chris53897](https://avatars.githubusercontent.com/u/7104259?v=4)](https://github.com/Chris53897 "Chris53897 (1 commits)")

---

Tags

deferred-executionphp-library

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/sanmai-later/health.svg)

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

PHPackages © 2026

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