

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用适用于 PHP 的 Amazon SDK 版本 3 中的分页结果
<a name="guide_paginators"></a>

某些 Amazon 服务操作会分页，并以截断的结果进行响应。例如，Amazon S3`ListObjects` 操作每次最多只能返回 1000 个对象。与此类似的操作（前缀通常为“list”或“describe”）需要利用令牌（或标记）参数生成后续请求，以检索完整的结果集。

 **Paginator** 是适用于 PHP 的 Amazon SDK的一种功能，充当此流程的抽象层，使开发人员能够更轻松地使用分页的 API。分页工具本质上是结果的迭代器。它们是使用客户端的 `getPaginator()` 方法创建的。如果调用 `getPaginator()`，您必须提供操作名称以及操作的参数（与执行操作时的方法相同）。您可以使用 `foreach` 迭代分页工具对象，以获得单个 `Aws\Result` 对象。

```
$results = $s3Client->getPaginator('ListObjects', [
    'Bucket' => 'amzn-s3-demo-bucket'
]);

foreach ($results as $result) {
    foreach ($result['Contents'] as $object) {
        echo $object['Key'] . "\n";
    }
}
```

## 分页工具对象
<a name="paginator-objects"></a>

`getPaginator()` 方法返回的对象是 `Aws\ResultPaginator` 类的实例。此类实现 PHP 的原生 `iterator` 接口，因此它可与 `foreach` 配合使用。它还可与迭代器函数 (如 `iterator_to_array`) 结合使用，并与 [SPL iterators](http://www.php.net/manual/en/spl.iterators.php)（如 `LimitIterator` 对象）良好集成。

分页工具对象每次只保留一“页”结果，并延时执行。这就意味着，请求数量是根据生成当前的结果页面的需求决定的。例如，Amazon S3`ListObjects` 操作每次最多只返回 1000 个对象，如果您的存储桶中有约 10000 个对象，分页工具共需执行 10 次请求。如果您需要迭代结果，则会在开始迭代时执行第一个请求，在循环第二次迭代时执行第二个请求，依此类推。

## 枚举结果数据
<a name="enumerating-data-from-results"></a>

分页工具对象拥有名为 `search()` 的方法，允许您为一组结果中的数据创建迭代器。您在调用 `search()` 时，请提供 [JMESPath 表达式](guide_jmespath.md)，指定要提取的数据。调用 `search()` 会返回迭代器，生成每页结果的表达式结果。在您迭代返回的迭代器时将延时评估。

以下示例与之前的代码示例等效，但使用 `ResultPaginator::search()` 方法可以更加精确。

```
$results = $s3Client->getPaginator('ListObjects', [
    'Bucket' => 'amzn-s3-demo-bucket'
]);

foreach ($results->search('Contents[].Key') as $key) {
    echo $key . "\n";
}
```

可使用 JMESPath 表达式执行非常复杂的操作。例如，如果您希望打印所有的对象键和常用前缀（即针对存储桶执行 `ls`），可以执行以下操作。

```
// List all prefixes ("directories") and objects ("files") in the bucket
$results = $s3Client->getPaginator('ListObjects', [
    'Bucket'    => 'amzn-s3-demo-bucket',
    'Delimiter' => '/'
]);

$expression = '[CommonPrefixes[].Prefix, Contents[].Key][]';
foreach ($results->search($expression) as $item) {
    echo $item . "\n";
}
```

## 异步分页
<a name="async-paginators"></a>

您可以提供 `each()` 的 `Aws\ResultPaginator` 方法的回调，异步迭代分页工具的结果。分页工具生成的每个值都会调用该回调。

```
$results = $s3Client->getPaginator('ListObjects', [
    'Bucket' => 'amzn-s3-demo-bucket'
]);

$promise = $results->each(function ($result) {
    echo 'Got ' . var_export($result, true) . "\n";
});
```

**注意**  
您可以使用 `each()` 方法将 API 操作的结果分页，同时异步发送其他请求。

底层基于协同程序的 Promise 会生成回调的非 null 返回值。这就意味着，您可以从回调返回 Promise，而在继续迭代其余项目之前，必须解决该回调，也就是要将其他 Promise 合并到迭代中。回调返回的最后一个非 null 值，是可满足对任何下游 Promise 所做的 Promise 的结果。如果返回的最后一个值是 Promise，解决该 Promise 所得的结果将满足或拒绝下游 Promise。

```
// Delete all keys that end with "Foo"
$promise = $results->each(function ($result) use ($s3Client) {
    if (substr($result['Key'], -3) === 'Foo') {
        // Merge this promise into the iterator
        return $s3Client->deleteAsync([
            'Bucket' => 'amzn-s3-demo-bucket',
            'Key'    => 'Foo'
        ]);
    }
});

$promise
    ->then(function ($result) {
        // Result would be the last result to the deleteAsync operation
    })
    ->otherwise(function ($reason) {
        // Reason would be an exception that was encountered either in the
        // call to deleteAsync or calls performed while iterating
    });

// Forcing a synchronous wait will also wait on all of the deleteAsync calls
$promise->wait();
```