This is an old revision of the document!
Dedicated StreamBucket class
- Date: 2024-01-19
- Author: Máté Kocsis kocsismate@php.net
- Status: Draft
- Target: next minor version (possibly PHP 8.4)
Introduction
When using user filters for stream processing, one of the fundamental concepts is stream buckets. A stream bucket is effectively a chunk of stream which can be extracted from bucket brigades. Most probably, this metaphor comes from firefighting bucket brigades who pass buckets of water to each other, standing in a chain.
Back to our original topic, here is an example for a very basic stream filter:
class simple_filter extends php_user_filter { function filter($in, $out, &$consumed, $closing) { while ($bucket = stream_bucket_make_writeable($in)) { $consumed += $bucket->datalen; stream_bucket_append($out, $bucket); } return PSFS_PASS_ON; } } stream_filter_register("simple", "simple_filter")
Disclaimer: the example is copy-pasted from https://stackoverflow.com/questions/27103269/what-is-a-bucket-brigade. Courtesy of Bob for providing such an exceptional answer to explain the behavior of user stream filters.
$in
and $out
are the two sides of the stream bucket brigade: items come from the former one, and you have to pass them to the latter one. The stream_bucket_make_writeable()
function can be used to get the bucket from the brigade, while the stream_bucket_new()
function is used to create a new bucket.
Discussion
There are a few slightly unfortunate issues how stream buckets are handled which are discussed in the following sections.
Lack of a dedicated class
The original problem why this RFC is submitted is that there is no dedicated class for stream buckets: stream_bucket_make_writeable()
and stream_bucket_new()
create just stdClass
instances and fill in their $bucket
, $data
, and $datalen
properties on the go.
$bucket = stream_bucket_new(fopen('php://temp', 'w+'), ''); var_dump($bucket); /* object(stdClass)#1 (3) { ["bucket"]=> resource(7) of type (userfilter.bucket) ["data"]=> string(0) "" ["datalen"]=> int(0) } */
As a consequence, their return type is no more specific than object
. Similarly, the second parameters of the stream_bucket_append()
and the stream_bucket_prepend()
functions (which expect stream buckets) accept any kind of objects by checking the existence of the necessary properties.
If we had a dedicated class for stream buckets then the advantages were the usual: better feedback could be provided by static analysis tools, while autocomplete in IDEs worked out of the box. Additionally, by having typed properties for the $data
and the $datalen
properties, we could get additional safeguards.
The $bucket property
The $bucket
property is a stream bucket resource which is about to be migrated to an object in a major PHP version as per Resource to object conversion. However, this property won't be useful anymore as soon as it becomes an object, since it can be inlined directly into the containing stream bucket class. Therefore, this RFC proposes to get rid of this property when the conversion happens. Until then, a deprecation is emitted in order to let people know about the planned change.
The $datalen property
The name of this property doesn't conform to the currently used naming conventions: we usually try to avoid abbreviations whenever possible (e.g. when the full name is not too verbose, and the abbreviation is not an extremely common term - like $id
). Since the difference between len
and length
is just 3 characters, I don't think that using this abbreviation is really worth it. Therefore, this RFC proposes to add a $dataLength
property.
Additionally, the $datalen
property would become deprecated in favor of $dataLength
in the subsequent minor or major version after the targeted version (possibly PHP 8.5 or PHP 9.0), and would be removed in the next to next major version (possibly PHP 10).
The proposed class
The final form of the proposed class is the following:
final class StreamBucket { /** * @var resource * @deprecated */ public $bucket; public string $data; /** @deprecated */ public int $datalen; public int $dataLength; }
Vote
The vote requires 2/3 majority in order to be accepted.