

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 第 3 適用於 PHP 的 AWS SDK 版中的串流
<a name="guide_streams"></a>

作為 [PSR-7](http://www.php-fig.org/psr/psr-7/) HTTP 訊息標準整合的一部分， 會在內部 適用於 PHP 的 AWS SDK 使用 [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 內容。

此串流裝飾項目會略過指定串流的前十個位元組，藉此移除 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 分段上傳 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!"
```