jessegall/laravel-memoize

1.4.0 2024-09-16 10:23 UTC

This package is auto-updated.

Last update: 2024-09-16 11:38:30 UTC


README

Latest Version on Packagist

Laravel Memoize 是一个库,它为 Laravel Eloquent 模型和其他 PHP 类提供了方法级别的缓存。它通过根据方法的参数缓存方法调用的结果来提高性能。

记忆化

记忆化是一种技术,用于缓存函数调用的结果,并在相同的输入再次发生时返回缓存的结果。

特性

  • 使用简单的特质易于实现
  • 与 Eloquent 模型和常规 PHP 类兼容
  • 支持基于方法参数的缓存
  • 同一模型的多个实例共享缓存
  • 在模型更新(或自定义事件)时自动使缓存失效
  • 可自定义不同存储选项的缓存驱动程序
  • 可自定义参数序列化以实现细粒度控制

目录

安装

您可以通过 Composer 安装此包

composer require jessegall/laravel-memoize

使用

  1. 在您的 Eloquent 模型或 PHP 类中使用 Memoize 特质
use JesseGall\LaravelMemoize\Memoize;

class YourModel extends Model
{
    use Memoize;

    // ... your model code
}
  1. 使用 memoize 函数包装您想记忆化的逻辑
public function expensiveCalculation($param1, $param2)
{
    return $this->memoize(function() use ($param1, $param2) {
        // Your expensive calculation here
        // For example:
        // - Complex database queries
        // - API calls
        // - Resource-intensive computations
        $result = // ... 
        return $result;
    });
}

基于提供给调用 memoize 的方法的参数记忆化回调的结果。在本例中,expensiveCalculation 的结果根据 $param1$param2 的值进行缓存。

记忆化与模型

当使用 Laravel Memoize 与 Eloquent 模型一起使用时,它的工作方式如下

  • 如果在模型中使用 Memoize 特质,记忆化将与模型的 ID(主键)相关联。
  • 如果将模型作为参数传递给记忆化方法,则模型的 ID 将用作缓存键的一部分。

这意味着

  • 同一模型的实例(相同 ID)将共享相同的记忆化结果。
  • 新查询的模型将使用可用的现有缓存结果。

以下是实际应用中的示例

class User extends Model
{
    use Memoize;

    public function expensiveCalculation()
    {
        return $this->memoize(function() {
            // Expensive operation here...
            return $result;
        });
    }
}

// Using Memoize in a model
$user1 = User::find(1);
$result1 = $user1->expensiveCalculation();

$user2 = User::find(1); // Different instance, same ID
$result2 = $user2->expensiveCalculation();

// $result1 and $result2 are the same, calculation done only once

// Passing a model as an argument
class Calculator
{
    use Memoize;

    public function complexCalculation(User $user)
    {
        return $this->memoize(function() use ($user) {
            // Complex calculation
            return $result;
        });
    }
}

$calculator = new Calculator();
// $result3 and $result4 are the same, calculation done only once
$result3 = $calculator->complexCalculation($user1);
$result4 = $calculator->complexCalculation($user2);

记忆化驱动程序

Laravel Memoize 可以使用不同的驱动程序来存储缓存结果。它自带两个内置驱动程序:MemoryDriverCacheDriver

可用驱动程序

  1. MemoryDriver(默认):将缓存结果存储在内存中,直到请求结束。

  2. CacheDriver:利用 Laravel 的缓存系统来存储记忆化结果。这允许结果在不同的请求之间持久化,并在连接到同一缓存存储的多台服务器之间共享。

⚠️ 针对 Laravel Octane 用户的重要通知

当与 MemoryDriver 一起使用 Laravel Octane 时,请注意,记忆化结果会跨由同一工作者处理的多个请求持久化。这可以提高性能,但也可能导致提供过时的数据。对于经常变化的数据,请实现适当的缓存清除机制以确保其新鲜性。

使用驱动程序

默认情况下,Laravel Memoize 使用 MemoryDriver。要使用不同的驱动程序,请覆盖模型或类中的 memoizeDriver 方法

use JesseGall\LaravelMemoize\Drivers\CacheDriver;
use JesseGall\LaravelMemoize\Drivers\DriverInterface;

class YourModel extends Model
{
    use Memoize;

    public static function memoizeDriver(): DriverInterface
    {
        return new CacheDriver(ttl: 60); // Cache results for 60 seconds
    }
    
}

创建自定义驱动程序

您可以通过实现 DriverInterface 创建自己的自定义驱动程序

  1. 创建自定义驱动类
use JesseGall\LaravelMemoize\Drivers\DriverInterface;

class CustomDriver implements DriverInterface
{
    // Implement the required methods
}
  1. 在您的模型或类中使用自定义驱动
class YourModel extends Model
{
    use Memoize;

    public static function memoizeDriver(): DriverInterface
    {
        return new CustomDriver();
    }
}

动态切换驱动程序

您可以基于特定条件动态切换驱动

class YourModel extends Model
{
    use Memoize;

    public static function memoizeDriver(): DriverInterface
    {
        if (config('app.env') === 'production') {
            return new CacheDriver();
        }

        return new MemoryDriver();
    }
}

参数序列化

Laravel Memoize 使用参数序列化器生成基于方法参数的唯一缓存键。您可以通过覆盖默认的 ArgumentSerializerFactoryInterface 或创建自己的 ArgumentSerializerFactoryInterface 实现来自定义此行为。

覆盖默认工厂

要覆盖默认的参数序列化器工厂,您可以在应用程序服务提供者中将您的自定义实现绑定到 ArgumentSerializerFactoryInterface

use App\Services\CustomArgumentSerializer;
use JesseGall\LaravelMemoize\ArgumentSerializerFactoryInterface;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(ArgumentSerializerFactoryInterface::class, CustomArgumentSerializerFactory::class);
    }
}

扩展默认工厂

如果您想扩展默认的 ArgumentSerializerFactory 以支持额外的类型或修改现有的序列化逻辑,您可以创建一个扩展 ArgumentSerializerFactory 的新类

use JesseGall\LaravelMemoize\ArgumentSerializerFactory;
use JesseGall\LaravelMemoize\Serializers\Serializer;
use App\Models\CustomModel;
use App\Services\CustomModelSerializer;

class ExtendedArgumentSerializerFactory extends ArgumentSerializerFactory
{
    public function make(mixed $arg): SerializerInterface
    {
        if ($arg instanceof CustomModel) {
            return new CustomModelSerializer();
        }

        return parent::make($arg);
    }
}

然后,在应用程序服务提供者中绑定您的扩展序列化器

use JesseGall\LaravelMemoize\ArgumentSerializerFactoryInterface;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(ArgumentSerializerFactoryInterface::class, ExtendedArgumentSerializerFactory::class);
    }
}

通过自定义参数序列化器,您可以控制不同类型的参数在生成缓存键时的序列化方式,从而对记忆过程有更细粒度的控制。

缓存

清除缓存

要手动清除特定实例的缓存

$model->memoizeForget();

自定义缓存失效事件

默认情况下,当模型被 '保存' 或删除时,模型的缓存会自动清除。您可以通过覆盖 memoizeCacheInvalidationEvents 方法来自定义触发缓存无效化的事件

class User extends Model
{
    use Memoize;

    public static function memoizeCacheInvalidationEvents(): array
    {
        return ['saved', 'deleted', 'custom-event'];
    }

    // ...
}

测试

要运行测试,请使用以下命令

vendor/bin/phpunit

贡献

欢迎贡献!请随时提交 Pull Request。

许可

此软件包是开源软件,采用 MIT 许可证 许可。