PHPackages                             spatie/once - 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. [Caching](/categories/caching)
4. /
5. spatie/once

ActiveLibrary[Caching](/categories/caching)

spatie/once
===========

A magic memoization function

3.1.2(5mo ago)1.4k29.1M—9%61[1 PRs](https://github.com/spatie/once/pulls)20MITPHPPHP ^8.0CI passing

Since Nov 6Pushed 1mo ago9 watchersCompare

[ Source](https://github.com/spatie/once)[ Packagist](https://packagist.org/packages/spatie/once)[ Docs](https://github.com/spatie/once)[ Fund](https://spatie.be/open-source/support-us)[ RSS](/packages/spatie-once/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (2)Versions (20)Used By (20)

[![Social Card of Once](/art/socialcard.png)](/art/socialcard.png)

A magic [memoization](https://en.wikipedia.org/wiki/Memoization) function
=========================================================================

[](#a-magic-memoization-function)

[![Latest Version on Packagist](https://camo.githubusercontent.com/72bd8532a3342fc7cdbf94b1d94f1f45da6d210452921126fb992f128c7a2d0d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7370617469652f6f6e63652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/spatie/once)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![Build Status](https://camo.githubusercontent.com/5cf02325a50dddf1af1b9e9bfe7902ebf8a263d28ace232bd6f2aa4aea4ebc37/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f7370617469652f6f6e63652f6d61737465722e7376673f7374796c653d666c61742d737175617265)](https://travis-ci.org/spatie/once)[![Quality Score](https://camo.githubusercontent.com/6a409384864163cc1a2c79c90fe23d987c05cdf1a5ee86025c9bb31f4507653b/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f7370617469652f6f6e63652e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/spatie/once)[![StyleCI](https://camo.githubusercontent.com/cbc6a9d4b2020e52a14008b0e21f32e8bed80ce9d5057bf6cb5e4609cb03d78b/68747470733a2f2f7374796c6563692e696f2f7265706f732f37333032303530392f736869656c643f6272616e63683d6d6173746572)](https://styleci.io/repos/73020509)[![Total Downloads](https://camo.githubusercontent.com/e2f1d82aaa1c884cd47110b9ab14497cb809025a211f76c3e97fad5151bb0723/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7370617469652f6f6e63652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/spatie/once)

This package contains a `once` function. You can pass a `callable` to it. Here's quick example:

```
$myClass = new class() {
    public function getNumber(): int
    {
        return once(function () {
            return rand(1, 10000);
        });
    }
};
```

No matter how many times you run `$myClass->getNumber()` inside the same request you'll always get the same number.

Are you a visual learner?
-------------------------

[](#are-you-a-visual-learner)

Under the hood, this package uses a PHP 8 Weakmap. [In this video](https://www.youtube.com/watch?v=-lFyHJqzfFU&list=PLjzBMxW2XGTwEwWumYBaFHy1z4W32TcjU&index=13), you'll see what a weakmap is, together with a nice demo of the package.

Support us
----------

[](#support-us)

[![](https://camo.githubusercontent.com/623b5833c1c62922be5c5f329eff2d82d2a3f24aa9e901fc92cc1cf886c9005e/68747470733a2f2f6769746875622d6164732e73332e65752d63656e7472616c2d312e616d617a6f6e6177732e636f6d2f6f6e63652e6a70673f743d31)](https://spatie.be/github-ad-click/once)

We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).

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

[](#installation)

You can install the package via composer:

```
composer require spatie/once
```

Usage
-----

[](#usage)

The `once` function accepts a `callable`.

```
$myClass = new class() {
    public function getNumber(): int
    {
        return once(function () {
            return rand(1, 10000);
        });
    }
};
```

No matter how many times you run `$myClass->getNumber()` you'll always get the same number.

The `once` function will only run once per combination of argument values the containing method receives.

```
class MyClass
{
    /**
     * It also works in static context!
     */
    public static function getNumberForLetter($letter)
    {
        return once(function () use ($letter) {
            return $letter . rand(1, 10000000);
        });
    }
}
```

So calling `MyClass::getNumberForLetter('A')` will always return the same result, but calling `MyClass::getNumberForLetter('B')` will return something else.

### Flushing the cache

[](#flushing-the-cache)

To flush the entire cache you can call:

```
Spatie\Once\Cache::getInstance()->flush();
```

### Disabling the cache

[](#disabling-the-cache)

In your tests you probably don't want to cache values. To disable the cache you can call:

```
Spatie\Once\Cache::getInstance()->disable();
```

You can re-enable the cache with

```
Spatie\Once\Cache::getInstance()->enable();
```

### Octane compatibility

[](#octane-compatibility)

> **Warning**
>
> This behaviour is in beta and needs to be tested by the community. You can find this topic [in discussion #79](https://github.com/spatie/once/discussions/79).

In order to have `once` working properly in an Octane environment, `Cache::getInstance()->flush()` must be called when `OperationTerminated` event is triggered. You can configure it in `config/octane.php` file:

```
// config/octane.php

OperationTerminated::class => [
    FlushTemporaryContainerInstances::class,
    // DisconnectFromDatabases::class,
    // CollectGarbage::class,

    FlushSpatieOnce::class, // we should create this class we have added here
],
```

And create the `FlushSpatieOnce:class`:

```
// app/Listeners/FlushSpatieOnce.php

use Spatie\Once\Cache;

class FlushSpatieOnce
{
    public function handle($event)
    {
        Cache::getInstance()->flush();
    }
}
```

Under the hood
--------------

[](#under-the-hood)

The `once` function will execute the given callable and save the result in the `$values` property of `Spatie\Once\Cache`. This class [is a singleton](https://github.com/spatie/once/blob/9decd70a76664ff451fb10f65ac360290a6a50e6/src/Cache.php#L15-L27). When we detect that `once` has already run before, we're just going to return the value stored inside [the `$values` weakmap](https://github.com/spatie/once/blob/9decd70a76664ff451fb10f65ac360290a6a50e6/src/Cache.php#L11) instead of executing the callable again.

The first thing it does is calling [`debug_backtrace`](http://php.net/manual/en/function.debug-backtrace.php). We'll use the output to determine in which function and class `once` is called and to get access to the `object` that function is running in. Yeah, we're already in voodoo-land. The output of the `debug_backtrace` is passed to a new instance of `Backtrace`. That class is just a simple wrapper, so we can work more easily with the backtrace.

```
$trace = debug_backtrace(
    DEBUG_BACKTRACE_PROVIDE_OBJECT, 2
)[1];

$backtrace = new Backtrace($trace);

$object = $backtrace->getObject();
```

Next, we calculate a `hash` of the backtrace. This hash will be unique per function `once` was called in and the values of the arguments that function receives.

```
$hash = $backtrace->getHash();
```

Finally, we will check if there's already a value stored for the given hash. If not, then execute the given `$callback` and store the result in the weakmap of `Spatie\Once\Cache`. In the other case, we just return the value from that cache (the `$callback` isn't executed).

```
public function has(object $object, string $backtraceHash): bool
{
    if (! isset($this->values[$object])) {

        return false;
    }

    return array_key_exists($backtraceHash, $this->values[$object]);
}
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

Testing
-------

[](#testing)

```
composer test
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details.

Security
--------

[](#security)

If you've found a bug regarding security please mail  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Freek Van der Herten](https://github.com/freekmurze)
- [All Contributors](../../contributors)

And a special thanks to [Caneco](https://twitter.com/caneco) for the logo ✨

Credit for the idea of the `once` function goes to [Taylor Otwell](https://twitter.com/taylorotwell/status/794622206567444481). The code for this package is based upon the code he was kind enough to share with us.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

72

—

ExcellentBetter than 100% of packages

Maintenance81

Actively maintained with recent releases

Popularity72

Solid adoption and visibility

Community45

Growing community involvement

Maturity77

Established project with proven stability

 Bus Factor1

Top contributor holds 61.1% 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 ~183 days

Recently: every ~401 days

Total

19

Last Release

174d ago

Major Versions

0.0.1 → 1.0.02016-11-07

1.1.0 → 2.0.02018-01-31

2.2.1 → 3.0.02020-11-03

PHP version history (4 changes)0.0.1PHP ^7.0

2.1.0PHP ^7.2

2.2.1PHP ^7.2|^8.0

3.0.0PHP ^8.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/7535935?v=4)[Spatie](/maintainers/spatie)[@spatie](https://github.com/spatie)

---

Top Contributors

[![freekmurze](https://avatars.githubusercontent.com/u/483853?v=4)](https://github.com/freekmurze "freekmurze (121 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (13 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (9 commits)")[![AdrianMrn](https://avatars.githubusercontent.com/u/12762044?v=4)](https://github.com/AdrianMrn "AdrianMrn (8 commits)")[![patinthehat](https://avatars.githubusercontent.com/u/5508707?v=4)](https://github.com/patinthehat "patinthehat (5 commits)")[![ahmedofali](https://avatars.githubusercontent.com/u/22732463?v=4)](https://github.com/ahmedofali "ahmedofali (4 commits)")[![ThibaudDauce](https://avatars.githubusercontent.com/u/1770543?v=4)](https://github.com/ThibaudDauce "ThibaudDauce (4 commits)")[![jimbojsb](https://avatars.githubusercontent.com/u/107836?v=4)](https://github.com/jimbojsb "jimbojsb (3 commits)")[![sebastiandedeyne](https://avatars.githubusercontent.com/u/1561079?v=4)](https://github.com/sebastiandedeyne "sebastiandedeyne (3 commits)")[![akoepcke](https://avatars.githubusercontent.com/u/5311185?v=4)](https://github.com/akoepcke "akoepcke (2 commits)")[![kurtextrem](https://avatars.githubusercontent.com/u/502146?v=4)](https://github.com/kurtextrem "kurtextrem (2 commits)")[![bastien-phi](https://avatars.githubusercontent.com/u/10199039?v=4)](https://github.com/bastien-phi "bastien-phi (2 commits)")[![sergejostir](https://avatars.githubusercontent.com/u/21297285?v=4)](https://github.com/sergejostir "sergejostir (2 commits)")[![AlexVanderbist](https://avatars.githubusercontent.com/u/6287961?v=4)](https://github.com/AlexVanderbist "AlexVanderbist (2 commits)")[![faisuc](https://avatars.githubusercontent.com/u/7190009?v=4)](https://github.com/faisuc "faisuc (2 commits)")[![peter279k](https://avatars.githubusercontent.com/u/9021747?v=4)](https://github.com/peter279k "peter279k (2 commits)")[![Nielsvanpach](https://avatars.githubusercontent.com/u/10651054?v=4)](https://github.com/Nielsvanpach "Nielsvanpach (1 commits)")[![bhulsman](https://avatars.githubusercontent.com/u/612651?v=4)](https://github.com/bhulsman "bhulsman (1 commits)")[![prateekkathal](https://avatars.githubusercontent.com/u/7609893?v=4)](https://github.com/prateekkathal "prateekkathal (1 commits)")[![romm](https://avatars.githubusercontent.com/u/6342901?v=4)](https://github.com/romm "romm (1 commits)")

---

Tags

cachemagicperformancephpspatiecallablecachememoizationonce

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/spatie-once/health.svg)

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

###  Alternatives

[psr/simple-cache

Common interfaces for simple caching

8.1k727.3M2.1k](/packages/psr-simple-cache)[psr/cache

Common interface for caching libraries

5.2k686.9M1.3k](/packages/psr-cache)[spatie/laravel-responsecache

Speed up a Laravel application by caching the entire response

2.8k8.2M51](/packages/spatie-laravel-responsecache)[react/cache

Async, Promise-based cache interface for ReactPHP

444112.4M40](/packages/react-cache)[spatie/blink

Cache that expires in the blink of an eye

1685.0M8](/packages/spatie-blink)[traderinteractive/memoize

A library for memoizing repeated function calls.

43125.7k](/packages/traderinteractive-memoize)

PHPackages © 2026

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