stellarwp/memoize

A flexible memoization library for memory caching.

1.1.0 2024-12-19 19:49 UTC

README

Tests PHPCS PHPStan Compatibility

A flexible memoization library for memory caching.

Table of Contents

Memoization

Memoization is the process of caching the results of expensive function calls so that they can be reused when the same inputs occur again.

Installation

It's recommended that you install Memoize as a project dependency via Composer:

composer require stellarwp/memoize

We actually recommend that this library gets included in your project using Strauss.

Luckily, adding Strauss to your composer.json is only slightly more complicated than adding a typical dependency, so checkout our strauss docs.

Notes on examples

All namespaces within the examples will be using the StellarWP\Memoize, however, if you are using Strauss, you will need to prefix these namespaces with your project's namespace.

Usage

Simple example

use StellarWP\Memoize\Memoizer;

$memoizer = new Memoizer();

$memoizer->set('foo', 'bar');

if ($memoizer->has('foo')) {
    echo $memoizer->get('foo'); // Outputs: bar
}

// Unsets foo from the memoization cache.
$memoizer->forget('foo');

Setting a nested structure

Memoize allows you to use dot notation to set, get, and forget values from a nested structure. This allows you to easily add/fetch values and then purge individual items or whole collections of items.

use StellarWP\Memoize\Memoizer;

$memoizer = new Memoizer();

$memoizer->set('foo.bar.bork', 'baz');

// This results in the following cache:
// [
//     'foo' => [
//         'bar' => [
//             'bork' => 'baz',
//         ],
//     ],
// ]

// You can fetch the value like so:
$value = $memoizer->get('foo.bar.bork');
echo $value; // Outputs: baz

// You can fetch anywhere up the chain:
$value = $memoizer->get('foo.bar');
echo $value; // Outputs: [ 'bork' => 'baz' ]

$value = $memoizer->get('foo');
echo $value; // Outputs: [ 'bar' => [ 'bork' => 'baz' ] ]

$value = $memoizer->get();
echo $value; // Outputs: [ 'foo' => [ 'bar' => [ 'bork' => 'baz' ] ] ]

Purging a nested structure

use StellarWP\Memoize\Memoizer;

$memoizer = new Memoizer();

$memoizer->set('foo.bar.bork', 'baz');
$memoizer->forget('foo.bar.bork');

// This results in the following cache:
// [
//     'foo' => [
//         'bar' => [],
//     ],
// ]

$memoizer->forget('foo.bar');

// This results in the following cache:
// [
//     'foo' => [],
// ]

$memoizer->forget('foo');

// This results in the following cache:
// []

$memoizer->forget();

// This results in the following cache:
// []

Caching with closures

Memoize also supports using closures as values that get resolved before setting in the cache.

use StellarWP\Memoize\Memoizer;

$memoizer = new Memoizer();

$memoizer->set('foo', static function () {
    return 'bar';
});

echo $memoizer->get('foo'); // Outputs: bar

Using with a dependency injection container

Project class

<?php

declare(strict_types=1);

namespace StellarWP\MyProject;

use StellarWP\Memoize\MemoizerInterface;

// Dependencies automatically auto-wired due to the definitions in ServiceProvider.php via
// $this->container->get( MyProjectClass::class )

/**
 * An example class inside your project using the Memoize library.
 */
class MyProjectClass
{

    private MemoizerInterface $memoizer;

    public function __construct( MemoizerInterface $memoizer )
    {
        $this->memoizer = $memoizer;
    }

    public function get( string $name ): string
    {
        $result = $this->memoizer->get( $name );

        if ( ! $result ) {
            $result = 'some very expensive operation';

            $this->memoizer->set( $name, $result );
        }

        return $result;
    }

    public function delete( string $name ): bool
    {
        $this->memoizer->forget( $name );

        // Run delete operation...

        return true;
    }
}

Service Provider

<?php

declare(strict_types=1);

namespace StellarWP\Memoize;

use StellarWP\ContainerContract\ContainerInterface;
use StellarWP\Memoize\Contracts\DriverInterface;
use StellarWP\Memoize\Contracts\MemoizerInterface;
use StellarWP\Memoize\Drivers\MemoryDriver;

/**
 * Container ServiceProvider to tell the DI Container how to build everything when another
 * instance is requested from the Container that uses our interface.
 *
 * @example $this->container->get( MyProjectClass::class );
 */
final class ServiceProvider
{
    private ContainerInterface $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function register(): void
    {
        $this->container->singleton( DriverInterface::class, MemoryDriver::class );
        $this->container->bind( MemoizerInterface::class, Memoizer::class );
    }
}

Drivers

Memoize comes with a single driver out of the box, but you can also create your own using the StellarWP\Memoize\Contracts\DriverInterface.

MemoryDriver

The MemoryDriver is a simple in-memory driver. Basically, contains an array property in the driver that holds the memoized values. You can manually specify the use of this driver or any other driver like so:

use StellarWP\Memoize\Memoizer;
use StellarWP\Memoize\Drivers\MemoryDriver;

$memoizer = new Memoizer(new MemoryDriver());