-
Notifications
You must be signed in to change notification settings - Fork 1
Filter streams
When reading from or writing data to a stream sometimes it may happen that not all data to read or not all data to be written is relevant for what you want to achieve. For example, a file you read may contain comment lines, and you don't want to ignore those comment lines. Normally, you would have the logic on what to ignore in your reading class:
while (!$inputStream->eof()) {
$line = $inputStream->readLine();
if (substr(0, 1, $line) !== '#') {
$this->processLine($line);
}
}
In this small example it may not be much work, but what if comment lines may also start with //
or there may even be comments stretching over more than one line as we have in PHP with /* comment over several lines ... */
. Now the logic might get a bit to complicated at this point. Stream filters to the rescue:
Applies to releases >= 4.0.0. For releases < 4.0.0 please see below.
$filterStream = new FilteredInputStream(
$inputStream,
function($line) { return substr($line, 0, 1) !== '#'; }
);
while (!$filterStream->eof()) {
$this->processLine($inputStream->readLine());
}
The second argument for stubbles\streams\filter\FilteredInputStream
can be any callable
or a predicate. The same applies to the stubbles\streams\filter\FilteredOutputStream
, just that the filter is applied to the data that is written.
Applies to releases < 4.0.0
$filterStream = new FilteredInputStream($inputStream, new CommentFilter());
while (!$filterStream->eof()) {
$this->processLine($inputStream->readLine());
}
The logic which line to pass out of the stream is now encapsulated in the CommentFilter
class and thus much easier to test. The comment filter class in turn only has to implement the net\stubbles\streams\filter\StreamFilter
interface with one little method:
/**
* Decides whether data should be filtered or not.
*
* @param string $data
* @return bool
*/
public function shouldFilter($data);
Here, $data
is the data just read from the underlying stream (or should be written to the underlying stream). The return value of this method signalizes whether this data should be filtered (return value true
) or not (return value false
).
With this filter in place, the net\stubbles\streams\filter\FilteredInputStream
and net\stubbles\streams\filter\FilteredOutputStream
can be put to use. Both have two constructor arguments: the input or output stream to decorate, and the filter to apply. While the FilteredInputStream
will use the filter to decide which data to pass on to the caller, the FilteredOutputStream
in turn decides which passed data should be written to the decorated output stream.
In case you like to combine several different filters net\stubbles\streams\filter\CompositeStreamFilter
can combine an arbitrary list of filters and then be passed as stream filter instance to the filtering streams.