solodkiy/memorize

纯函数的简单缓存

0.1.0 2016-11-21 19:22 UTC

This package is auto-updated.

Last update: 2024-08-29 04:25:30 UTC


README

Build Status Latest Stable Version Total Downloads

Memorize 是 PHP 的 Python @lazy 装饰器的类似物。

Memorize 为闭包提供简单的参数缓存。它可以用来创建懒加载函数。函数接受闭包和可选的参数 paramsHash。如果之前已经用相同的参数运行了闭包,Memorize 将直接从缓存中返回结果,而无需再次调用闭包。第一次调用时,结果将被计算并存储在缓存中。

缓存存储在全局空间中,用于静态方法和简单函数。对于对象方法中定义的闭包,缓存将存储在这个对象中(两个对象有不同的缓存)。根据设计,缓存仅在脚本运行期间存储。无法设置缓存的有效期或使缓存失效。Memorize 会自动为具有标量参数的闭包计算 paramsHash。如果你的闭包有对象作为参数,你必须计算并传递 paramsHash 作为第二个参数。(参见MemorizeInObjectTest::correctAddDaysToTime测试)

请注意,Memorize 通过文件名、闭包声明的起始行和结束行来计算闭包的哈希值。如果你在一行中声明了两个闭包(例如:在代码混淆之后),Memorize 可能无法正确工作。

安装

composer require solodkiy/memorize

示例

使用 memorize 的单例

之前

class Singleton
{
    /**
     * @var Singleton
     */
    private static $instance;
    
    private function __construct()
    {
        // private
    }

    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new Singleton();
        }
        return self::$instance;
    }
}

之后

class Singleton
{
    private function __construct()
    {
        // private
    }

    public static function getInstance()
    {
        return memorize(function() {
            return new Singleton();
        });
    }
}

懒递归阶乘函数

function factorial($number)
{
    return memorize(function () use ($number) {
        if ($number <= 0) {
            throw new \InvalidArgumentException('Number must be natural');
        }
        return ($number == 1)
            ? 1
            : $number * factorial($number - 1);
    });
}

参见 MemorizeInFunctionTest

它也正确地在对象中工作。

之前

class TableGateway
{
    /**
     * @var array
     */ 
    private $cacheStatistic = [];
    
    public function getA($accountId)
    {
        return $this->calculateStatistic($accountId)['a'];
    }
    
    public function getB($accountId)
    {
        return $this->calculateStatistic($accountId)['b'];
    }
    
    private function calculateStatistic($accountId)
    {
        if (!isset($this->cacheStatistic[$accountId])) {
            $sql = 'SELECT AVG(price) AS a ...';
            $result = $this->db->getRows($sql, [$accountId]);
            $this->cacheStatistic[$accountId] = $result;
        }
        return $this->cacheStatistic[$accountId];
    }
}

之后

class TableGateway
{
    public function getA($accountId)
    {
        return $this->calculateStatistic($accountId)['a'];
    }
    
    public function getB($accountId)
    {
        return $this->calculateStatistic($accountId)['b'];
    }
    
    private function calculateStatistic($accountId)
    {
        return memorize(function () use ($accountId) {
            $sql = 'SELECT AVG(price) AS a ...';
            return $this->db->getRows($sql, [$accountId]);
        });
    }
}

参见 MemorizeFunctionInObjectTest::testTwoObjects