Skip to content

Commit

Permalink
Merge pull request #1 from stellarwp/feature/closure-support
Browse files Browse the repository at this point in the history
Support closures as values for `::set()`
  • Loading branch information
borkweb authored Dec 19, 2024
2 parents b607d97 + 2818fee commit 0c2fe05
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 289 deletions.
172 changes: 133 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@

A flexible memoization library for memory caching.

## Table of Contents

- [Memoization](#memoization)
- [Installation](#installation)
- [Notes on examples](#notes-on-examples)
- [Usage](#usage)
- [Simple example](#simple-example)
- [Setting a nested structure](#setting-a-nested-structure)
- [Purging a nested structure](#purging-a-nested-structure)
- [Caching with closures](#caching-with-closures)
- [Using with a dependency injection container](#using-with-a-dependency-injection-container)
- [Drivers](#drivers)
- [MemoryDriver](#memorydriver)

## Memoization

[Memoization](https://en.wikipedia.org/wiki/Memoization) is the process of caching the results of expensive function calls so that they can be reused when the same inputs occur again.
Expand All @@ -29,26 +43,30 @@ All namespaces within the examples will be using the `StellarWP\Memoize`, howeve
### Simple example

```php
use StellarWP\Memoize\Memoize;
use StellarWP\Memoize\Memoizer;

$memoizer = new Memoizer();

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

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

// Unsets foo from the memoization cache.
Memoize::forget('foo');
$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.

```php
use StellarWP\Memoize\Memoize;
use StellarWP\Memoize\Memoizer;

$memoizer = new Memoizer();

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

// This results in the following cache:
// [
Expand All @@ -60,27 +78,29 @@ Memoize::set('foo.bar.bork', 'baz');
// ]

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

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

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

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

#### Purging a nested structure

```php
use StellarWP\Memoize\Memoize;
use StellarWP\Memoize\Memoizer;

Memoize::set('foo.bar.bork', 'baz');
Memoize::forget('foo.bar.bork');
$memoizer = new Memoizer();

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

// This results in the following cache:
// [
Expand All @@ -89,67 +109,141 @@ Memoize::forget('foo.bar.bork');
// ],
// ]

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

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

Memoize::forget('foo');
$memoizer->forget('foo');

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

Memoize::forget();
$memoizer->forget();

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

### Caching an expensive execution
### Caching with closures

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

```php
use StellarWP\Memoize\Memoize;
use StellarWP\Memoize\Memoizer;

function my_expensive_function() {
$key = __FUNCTION__;
$value = Memoize::get($key);
$memoizer = new Memoizer();

if ( ! $value ) {
// Do some crazy expensive stuff to set:
$memoizer->set('foo', static function () {
return 'bar';
});

$value = $thing;
echo $memoizer->get('foo'); // Outputs: bar
```

### Using with a dependency injection container

#### Project class

```php
<?php

Memoize::set($key, $value);
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;
}

return $value;
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;
}
}
```

## Drivers
#### Service Provider

Memoize comes with a few drivers out of the box, but you can also create your own.
```php
<?php

### MemoryDriver
declare(strict_types=1);

The `MemoryDriver` is a simple in-memory driver. Basically, there's a static variable in the driver that holds the memoized values. You can manually specify the use of this driver like so:
namespace StellarWP\Memoize;

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

Config::setDriver(new 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 );
}
}
```

### WpCacheDriver
## Drivers

The `WpCacheDriver` is the default driver and uses WordPress's `wp_cache_set` and `wp_cache_get` functions and stores all of the memoized values in a single cache entry. Getting and setting memoized values is done by fetching from cache, manipulating (if needed), and saving back to cache (if needed).
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:

```php
use StellarWP\Memoize\Config;
use StellarWP\Memoize\Drivers\WpCacheDriver;
use StellarWP\Memoize\Memoizer;
use StellarWP\Memoize\Drivers\MemoryDriver;

Config::setDriver(new WpCacheDriver());
$memoizer = new Memoizer(new MemoryDriver());
```
61 changes: 0 additions & 61 deletions src/Memoize/Config.php

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace StellarWP\Memoize\Drivers\Contracts;
namespace StellarWP\Memoize\Contracts;

interface DriverInterface
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@

declare(strict_types=1);

namespace StellarWP\Memoize;
namespace StellarWP\Memoize\Contracts;

final class Memoize
interface MemoizerInterface
{
/**
* Get a value from the memoization cache.
*
* @param ?string $key The cache key using dot notation. If null, the entire cache will be returned.
* @return mixed
*/
public static function get(?string $key = null)
{
return Config::getDriver()->get($key);
}
public function get(?string $key = null);

/**
* Set a value in the memoization cache.
Expand All @@ -24,30 +21,21 @@ public static function get(?string $key = null)
* @param mixed $value The value to store in the cache.
* @return void
*/
public static function set(string $key, $value): void
{
Config::getDriver()->set($key, $value);
}
public function set(string $key, $value): void;

/**
* Check if a key exists in the memoization cache.
*
* @param string $key The cache key using dot notation.
* @return boolean
* @return bool
*/
public static function has(string $key): bool
{
return Config::getDriver()->has($key);
}
public function has(string $key): bool;

/**
* Remove a key from the memoization cache.
*
* @param ?string $key The cache key using dot notation. If null, the entire cache will be cleared.
* @return void
*/
public static function forget(?string $key = null): void
{
Config::getDriver()->forget($key);
}
public function forget(?string $key = null): void;
}
Loading

0 comments on commit 0c2fe05

Please sign in to comment.