

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

# 适用于 PHP 的 AWS SDK 版本 3 中的流
<a name="guide_streams"></a>

由于 [ 集成了 ](http://www.php-fig.org/psr/psr-7/)PSR-7适用于 PHP 的 AWS SDK HTTP 消息标准，因此它在内部使用 [PSR-7 StreamInterface](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Psr.Http.Message.StreamInterface.html)，作为对 [PHP 流](http://php.net/manual/en/intro.stream.php)的抽象。命令的输入字段如果定义为 blob（例如 `Body`S3::PutObject 命令[的 ](https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putobject) 参数），字符串、PHP 流资源或 `Psr\Http\Message\StreamInterface` 的实例均可满足该命令。

**警告**  
开发工具包会负责处理所有作为命令输入参数提供的原始 PHP 流资源。将代表您使用并关闭流。  
如果您需要在开发工具包操作和代码之间共享流，请先将它包装在 `GuzzleHttp\Psr7\Stream` 的实例中，再作为参数包含在命令中。开发工具包会使用流，因此您的代码需要考虑流的内部游标的移动。Guzzle 流在被 PHP 的垃圾回收器销毁时会对底层流资源调用 `fclose`，因此您无需自己关闭流。

## 流装饰器
<a name="stream-decorators"></a>

Guzzle 提供多种流装饰器，可用于控制开发工具包和 Guzzle 与作为命令输入参数提供的流资源进行交互的方式。这些装饰器可修改处理程序在给定流上读取和搜寻的方式。以下是列表的一部分，在 [GuzzleHttpPsr7 存储库](https://github.com/guzzle/psr7)中可以找到更多内容。

### AppendStream
<a name="appendstream"></a>

 [GuzzleHttp\$1Psr7\$1AppendStream](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-GuzzleHttp.Psr7.AppendStream.html) 

从多个流中依次读取。

```
use GuzzleHttp\Psr7;

$a = Psr7\stream_for('abc, ');
$b = Psr7\stream_for('123.');
$composed = new Psr7\AppendStream([$a, $b]);

$composed->addStream(Psr7\stream_for(' Above all listen to me'));

echo $composed(); // abc, 123. Above all listen to me.
```

### CachingStream
<a name="cachingstream"></a>

 [GuzzleHttp\$1Psr7\$1CachingStream](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-GuzzleHttp.Psr7.CachingStream.html) 

允许在不可搜寻的流上搜寻之前读取的字节。如果由于需要倒回流导致未能传输不可搜寻的正文（例如重定向后），它非常有用。从远程流中读取的数据将缓存在 PHP 临时流中，这样上次读取的字节将首先缓存到内存中，然后再缓存到磁盘上。

```
use GuzzleHttp\Psr7;

$original = Psr7\stream_for(fopen('http://www.google.com', 'r'));
$stream = new Psr7\CachingStream($original);

$stream->read(1024);
echo $stream->tell();
// 1024

$stream->seek(0);
echo $stream->tell();
// 0
```

### InflateStream
<a name="inflatestream"></a>

 [GuzzleHttp\$1Psr7\$1InflateStream](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-GuzzleHttp.Psr7.InflateStream.html) 

使用 PHP 的 zlib.inflate 筛选条件来增加或减少使用 gzip 压缩的内容。

这个流装饰器会跳过给定流的前 10 个字节，以删除 gzip 标头，将提供的流转换为 PHP 流资源，然后附加 zlib.inflate 筛选器。然后该流将会转换回 Guzzle 流资源，用作 Guzzle 流。

### LazyOpenStream
<a name="lazyopenstream"></a>

 [GuzzleHttp\$1Psr7\$1LazyOpenStream](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-GuzzleHttp.Psr7.LazyOpenStream.html) 

仅在流中发生 I/O 操作后，再延时读取或写入已打开的文件。

```
use GuzzleHttp\Psr7;

$stream = new Psr7\LazyOpenStream('/path/to/file', 'r');
// The file has not yet been opened...

echo $stream->read(10);
// The file is opened and read from only when needed.
```

### LimitStream
<a name="limitstream"></a>

 [GuzzleHttp\$1Psr7\$1LimitStream](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-GuzzleHttp.Psr7.LimitStream.html) 

用于读取现有流对象的子集或分片。如需将较大文件拆分为小块，以便分段发送（例如 Amazon S3 Multipart Upload API），那么它很有用。

```
use GuzzleHttp\Psr7;

$original = Psr7\stream_for(fopen('/tmp/test.txt', 'r+'));
echo $original->getSize();
// >>> 1048576

// Limit the size of the body to 1024 bytes and start reading from byte 2048
$stream = new Psr7\LimitStream($original, 1024, 2048);
echo $stream->getSize();
// >>> 1024
echo $stream->tell();
// >>> 0
```

### NoSeekStream
<a name="noseekstream"></a>

 [GuzzleHttp\$1Psr7\$1NoSeekStream](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-GuzzleHttp.Psr7.NoSeekStream.html) 

对流进行包装，不允许搜寻。

```
use GuzzleHttp\Psr7;

$original = Psr7\stream_for('foo');
$noSeek = new Psr7\NoSeekStream($original);

echo $noSeek->read(3);
// foo
var_export($noSeek->isSeekable());
// false
$noSeek->seek(0);
var_export($noSeek->read(3));
// NULL
```

### PumpStream
<a name="pumpstream"></a>

 [GuzzleHttp\$1Psr7\$1PumpStream](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-GuzzleHttp.Psr7.PumpStream.html) 

提供只读流，从 PHP 可调用函数中提取数据。

如果调用提供的可调用函数，PumpStream 会向该可调用函数传递请求读取的数据量。可调用函数可以选择忽略此值，并返回少于请求或多于请求的字节。提供的可调用函数返回的所有额外数据将缓存于内部，直到使用 PumpStream 的 read() 函数耗尽。如果没有可读取的数据，提供的可调用函数必须返回 false。

### 实施流装饰器
<a name="implementing-stream-decorators"></a>

由于有了 [GuzzleHttp\$1Psr7\$1StreamDecoratorTrait](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-GuzzleHttp.Psr7.StreamDecoratorTrait.html)，创建流装饰器变得非常容易。此特性通过代理底层流，提供实施 `Psr\Http\Message\StreamInterface` 的方法。只需 `use` `StreamDecoratorTrait`，并实施您的自定义方法。

例如，假设我们希望在每次读取流的最后一个字节时调用特定的函数。这可通过覆盖 `read()` 方法实施。

```
use Psr\Http\Message\StreamInterface;
use GuzzleHttp\Psr7\StreamDecoratorTrait;

class EofCallbackStream implements StreamInterface
{
    use StreamDecoratorTrait;

    private $callback;

    public function __construct(StreamInterface $stream, callable $cb)
    {
        $this->stream = $stream;
        $this->callback = $cb;
    }

    public function read($length)
    {
        $result = $this->stream->read($length);

        // Invoke the callback when EOF is hit
        if ($this->eof()) {
            call_user_func($this->callback);
        }

        return $result;
    }
}
```

此装饰器可添加到任何现有流中，使用方法与以下示例类似。

```
use GuzzleHttp\Psr7;

$original = Psr7\stream_for('foo');

$eofStream = new EofCallbackStream($original, function () {
    echo 'EOF!';
});

$eofStream->read(2);
$eofStream->read(1);
// echoes "EOF!"
$eofStream->seek(0);
$eofStream->read(3);
// echoes "EOF!"
```