本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
版本 3 中的分页器 AWS SDK for PHP
某些 AWS 服务操作会被分页并以截断结果作为响应。例如,Amazon S3ListObjects
操作每次最多只能返回 1000 个对象。与此类似的操作(前缀通常为“list”或“describe”)需要利用令牌(或标记)参数生成后续请求,以检索完整的结果集。
分页器是其中的一项功能,它 AWS SDK for PHP 可以作为对这个过程的抽象,使开发人员更容易使用分页。APIs分页工具本质上是结果的迭代器。它们是使用客户端的 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"; } }
分页工具对象
getPaginator()
方法返回的对象是 Aws\ResultPaginator
类的实例。这个类实现PHP了原生iterator
接口,这就是它使用的原因foreach
。它也可以与迭代器函数(比如)一起使用iterator_to_array
,并且可以很好地与SPL对象之类的迭代器LimitIterator
分页工具对象每次只保留一“页”结果,并延时执行。这就意味着,请求数量是根据生成当前的结果页面的需求决定的。例如,Amazon S3ListObjects
操作每次最多只返回 1000 个对象,如果您的存储桶中有约 10000 个对象,分页工具共需执行 10 次请求。如果您需要迭代结果,则会在开始迭代时执行第一个请求,在循环第二次迭代时执行第二个请求,依此类推。
枚举结果数据
分页工具对象拥有名为 search()
的方法,允许您为一组结果中的数据创建迭代器。当您调用时search()
,请提供一个JMESPath表达式来指定要提取的数据。调用 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"; }
异步分页
您可以提供 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();