koafan/deferred-collection

具有延迟操作和执行的 PHP 集合

1.0.0 2017-07-13 05:08 UTC

This package is not auto-updated.

Last update: 2024-09-29 03:21:16 UTC


README

Minimum PHP Version Latest Stable Version Build Status Coverage Status StyleCI License: MIT composer.lock

介绍和动机

该库的主要目的是将集合项上不同操作的执行推迟到您的应用程序真正需要的时候。事实证明,应用程序性能不佳的原因往往是执行了不必要的集合操作。此外,一次对整个集合执行重操作通常非常低效,并且占用太多内存。因此,让我们看看以下代码示例

<?php 

$query  = 'SELECT id, name, department FROM my_table';
$result = $mysqli->query($query, MYSQLI_USE_RESULT)
$models = [];

// ... Dummy code ...
while ($record = $result->fetch_assoc()) {
    if ($record['department'] === 'developers') {
        $models[] = new MyModel($record);
    }
}

// ...
if (somethingWrongHappened()) {
    throw new RuntimeException('Error happened!!!');
}
// ...

// ... Somewhere in the view ... //
foreach ($models as $model) {
    echo "<div>{$model->id} - {$model->name}</div>";

    if (isEnough()) {
        break;
    }
}

这段代码有几个问题。

  1. 首先,它试图一次性将所有模型读取到进程内存中。所以如果找到1000条记录,它将尝试将所有1000条都读取到进程内存中。
  2. 其次,如果发生somethingWrongHappened(),则可能根本不需要此查询,因为在这种情况下,将抛出错误。因此,在这种情况下,数据库查询及其结果是资源浪费。
  3. 当然,在数据渲染过程中,我们可能根本不需要迭代所有查询,即使我们已经从数据库中检索了它们。

因此,延迟集合旨在解决这个问题。所有操作实际上只有在开始迭代集合时才会执行。例如

<?php

$collection = new DeferredCollection(function() {
    $query  = 'SELECT id, name, department FROM my_table';
    $result = $mysqli->query($query, MYSQLI_USE_RESULT)

    while ($record = $result->fetch_assoc()) {
        yield $record;
    }
});

// The collection is not going to be executed yet
$collection
    ->matchProperty('department', 'developers')
    ->instantiate(MyModel::class)

// ...
if (somethingWrongHappened()) {
    throw new RuntimeException('Error happened!!!');
}
// ...

// NOW the collection is going to be executed, but only 1 record per time will be processed
// we are not collecting all the records in a single array as it was done before,
// instead of that, Deferred Collection uses generators for all the data manipulations behind the scenes
foreach ($collection as $model) {
    echo "<div>{$model->id} - {$model->name}</div>";

    if (isEnough()) {
        break;
    }
}