leinonen/php-dataloader

Facebook DataLoader 的 PHP 版本

2.1.0 2021-09-23 20:21 UTC

README

将 Facebook 的 DataLoader 转换为 PHP 版本。从 ReactPHP 获得异步超级能力。

DataLoader 是一个通用工具,可用于作为您应用程序数据获取层的一部分,通过批处理和缓存,提供对各种远程数据源(如数据库或 Web 服务)的简化且一致的 API。

Build Status Code Coverage Latest Stable Version Total Downloads Latest Unstable Version License Scrutinizer Code Quality SensioLabsInsight

目录

安装

使用 Composer 在项目的根目录中安装此包。

composer require leinonen/php-dataloader

用法

要创建一个加载器,您必须提供一个批处理函数、ReactPHP 的内部缓存和全局事件循环。要更好地了解 ReactPHP 事件循环是什么以及如何使用它,请参阅它的 文档

use leinonen\DataLoader\Dataloader;
use React\EventLoop\Factory;

$eventLoop = Factory::create();

$bandLoader = new DataLoader(
    function ($keys) {
        // Batch load bands with given keys.
    },
    $eventLoop,
    new CacheMap()
);

然后从加载器中加载数据。DataLoader 将合并事件循环中发生的所有单个加载,然后使用所有请求的键调用您的批处理函数。

$bandLoader->load(1)->then(function ($band) {
    echo "Band #${$band->getId()} loaded";
});

$bandLoader->load(2)->then(function ($band) {
    echo "Band #${$band->getId()} loaded";
});

$eventLoop->run(); // The batch function will be called with keys [1, 2] at this point

调用加载函数返回 React\Promise\Promise。要更好地了解如何在 PHP 中使用承诺,请参阅 ReactPHP 文档

批处理函数

批处理加载函数接受一个键的数组,并必须返回一个解析为值数组的 Promise。还有一些其他约束条件

  • 值的数组必须与键的数组长度相同。
  • 值的数组中的每个索引必须与键的数组中的相同索引对应,即批处理加载结果的顺序必须与给出的键的顺序相同。

例如,如果您的批处理函数提供了键数组:[2, 9, 6, 1],并且批处理加载结果如下:

[
    ['id' => 1, 'name' => 'Mojo Waves'],
    ['id' => 2, 'name' => 'Pleasure Hazard'],
    ['id' => 9, 'name' => 'Leka'],
]

加载的结果顺序与请求的顺序不同,这在大多数关系型数据库中很常见。此外,键 6 的结果被省略了,我们可以将其解释为该键不存在值。

为了满足批处理函数的约束,我们需要修改结果,使其长度与键的数组相同,并重新排序以确保每个索引与原始键对齐。

[
    ['id' => 2, 'name' => 'Pleasure Hazard'],
    ['id' => 9, 'name' => 'Leka'],
    null,
    ['id' => 1, 'name' => 'Mojo Waves'],
]

缓存

DataLoader 为您应用程序的单个请求中发生的所有加载提供缓存。在用给定键调用 load() 一次之后,结果将缓存起来以消除重复加载。

除了减轻数据存储的负载外,按请求缓存结果还会创建更少的对象,这可能有助于减轻应用程序的内存压力。

$promise1 = $bandLoader->load(1);
$promise2 = $bandLoader->load(2);

($promise1 === $promise2) // true

DataLoader 缓存不能替代 Redis、Memcache 或任何其他共享应用程序级缓存。DataLoader 首先是一个数据加载机制,其缓存仅用于在您应用程序的单个请求的上下文中避免重复加载相同的数据。为此,它利用构造函数参数中给出的 CacheMap。

此包提供了一个简单的 CacheMap (leinonen\DataLoader\CacheMap) 实现,用于与 DataLoader 一起使用。您还可以使用您自定义的 CacheMap 与各种不同的 缓存算法 一起使用,通过实现 leinonen\DataLoader\CacheMapInterface

与常见 ORM 的用法

Eloquent (Laravel)

$userByIdLoader = new DataLoader(function ($ids) {
  $users = User::findMany($ids);

  // Make sure that the users are on the same order as the given ids for the loader
  $orderedUsers = collect($ids)->map(function ($id) use ($users) {
    return $users->first(function ($user) use ($id) {
      return $user->id === $id;
    });
  });

   return \React\Promise\resolve($orderedUsers);
}, $eventLoopFromIoCContainer, $cacheMapFromIoCContainer);

ActiveRecord (Yii2)

$usersByIdLoader = new DataLoader(function ($ids) {
    $users = User::find()->where(['id' => $ids])->all();

    $orderedUsers = \array_map(function ($id) use ($users) {
        foreach ($users as $user) {
            if ($user->id === $id) {
                return $user;
            }
        }

        return null;
    }, $ids);

    return \React\Promise\resolve($orderedUsers);
}, $eventLoopFromDiContainer, $cacheMapImplementationFromDiContainer);

API

load($key)

加载一个键,返回表示该键的值的 Promise

  • @param mixed $key 要加载的键值。

loadMany($keys)

加载多个键,承诺返回一个值数组。

这相当于更冗长的

$promises = \React\Promise\all([
  $myLoader->load('a'),
  $myLoader->load('b')
]);
  • @param array $keys: 要加载的键值数组。

clear($key)

如果存在,从缓存中清除 $key 的值。

  • @param mixed key: 要清除的键值。

clearAll()

清除整个缓存。

prime($key, $value)

使用提供的键和值预加载缓存。如果键已存在,则不进行更改。(要强制预加载缓存,请先使用 $loader->clear($key)->prime($key, $value) 清除键)。