Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to require PHP 7.1+ #175

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ jobs:
- 7.3
- 7.2
- 7.1
- 7.0
- 5.6
- 5.5
- 5.4
- 5.3
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
Expand Down Expand Up @@ -52,23 +47,3 @@ jobs:
- run: composer install
- run: vendor/bin/phpunit --coverage-text
- run: time php examples/91-benchmark-throughput.php

PHPUnit-hhvm:
name: PHPUnit (HHVM)
runs-on: ubuntu-22.04
continue-on-error: true
steps:
- uses: actions/checkout@v4
- run: cp "$(which composer)" composer.phar && ./composer.phar self-update --2.2 # downgrade Composer for HHVM
- name: Run hhvm composer.phar install
uses: docker://hhvm/hhvm:3.30-lts-latest
with:
args: hhvm composer.phar install
- name: Run hhvm vendor/bin/phpunit
uses: docker://hhvm/hhvm:3.30-lts-latest
with:
args: hhvm vendor/bin/phpunit
- name: Run time hhvm examples/91-benchmark-throughput.php
uses: docker://hhvm/hhvm:3.30-lts-latest
with:
args: bash -c "time hhvm examples/91-benchmark-throughput.php"
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ By default, this will call `end()` on the destination stream once the
source stream emits an `end` event. This can be disabled like this:

```php
$source->pipe($dest, array('end' => false));
$source->pipe($dest, ['end' => false]);
```

Note that this only applies to the `end` event.
Expand Down Expand Up @@ -1126,7 +1126,7 @@ $through = new ThroughStream(function ($data) {
});
$through->on('data', $this->expectCallableOnceWith("[2, true]\n"));

$through->write(array(2, true));
$through->write([2, true]);
```

The callback function is allowed to throw an `Exception`. In this case,
Expand Down Expand Up @@ -1217,9 +1217,8 @@ composer require react/stream:^3@dev
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.

This project aims to run on any platform and thus does not require any PHP
extensions and supports running on legacy PHP 5.3 through current PHP 8+ and HHVM.
It's *highly recommended to use PHP 7+* for this project due to its vast
performance improvements.
extensions and supports running on PHP 7.1 through current PHP 8+.
It's *highly recommended to use the latest supported PHP version* for this project.

## Tests

Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
}
],
"require": {
"php": ">=5.3.8",
"php": ">=7.1",
"react/event-loop": "^1.2",
"evenement/evenement": "^3.0 || ^2.0 || ^1.0"
},
"require-dev": {
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
"phpunit/phpunit": "^9.6 || ^7.5",
"clue/stream-filter": "~1.2"
},
"autoload": {
Expand Down
2 changes: 1 addition & 1 deletion examples/01-http.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

require __DIR__ . '/../vendor/autoload.php';

$host = isset($argv[1]) ? $argv[1] : 'www.google.com';
$host = $argv[1] ?? 'www.google.com';

// connect to tcp://www.google.com:80 (blocking call!)
// for illustration purposes only, should use react/http-client or react/socket instead!
Expand Down
2 changes: 1 addition & 1 deletion examples/02-https.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

require __DIR__ . '/../vendor/autoload.php';

$host = isset($argv[1]) ? $argv[1] : 'www.google.com';
$host = $argv[1] ?? 'www.google.com';

// connect to tls://www.google.com:443 (blocking call!)
// for illustration purposes only, should use react/http-client or react/socket instead!
Expand Down
6 changes: 3 additions & 3 deletions examples/91-benchmark-throughput.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
}

$args = getopt('i:o:t:');
$if = isset($args['i']) ? $args['i'] : '/dev/zero';
$of = isset($args['o']) ? $args['o'] : '/dev/null';
$t = isset($args['t']) ? $args['t'] : 1;
$if = $args['i'] ?? '/dev/zero';
$of = $args['o'] ?? '/dev/null';
$t = $args['t'] ?? 1;

// passing file descriptors requires mapping paths (https://bugs.php.net/bug.php?id=53465)
$if = str_replace('/dev/fd/', 'php://fd/', $if);
Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml.legacy
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- PHPUnit configuration file with old format for legacy PHPUnit -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/4.8/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/7.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<testsuites>
Expand Down
10 changes: 5 additions & 5 deletions src/CompositeStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ public function __construct(ReadableStreamInterface $readable, WritableStreamInt
return;
}

Util::forwardEvents($this->readable, $this, array('data', 'end', 'error'));
Util::forwardEvents($this->writable, $this, array('drain', 'error', 'pipe'));
Util::forwardEvents($this->readable, $this, ['data', 'end', 'error']);
Util::forwardEvents($this->writable, $this, ['drain', 'error', 'pipe']);

$this->readable->on('close', array($this, 'close'));
$this->writable->on('close', array($this, 'close'));
$this->readable->on('close', [$this, 'close']);
$this->writable->on('close', [$this, 'close']);
}

public function isReadable()
Expand All @@ -46,7 +46,7 @@ public function resume()
$this->readable->resume();
}

public function pipe(WritableStreamInterface $dest, array $options = array())
public function pipe(WritableStreamInterface $dest, array $options = [])
{
return Util::pipe($this, $dest, $options);
}
Expand Down
57 changes: 13 additions & 44 deletions src/DuplexResourceStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function __construct($stream, LoopInterface $loop = null, $readChunkSize

// ensure resource is opened for reading and wrting (fopen mode must contain "+")
$meta = \stream_get_meta_data($stream);
if (isset($meta['mode']) && $meta['mode'] !== '' && \strpos($meta['mode'], '+') === false) {
if (\strpos($meta['mode'], '+') === false) {
throw new InvalidArgumentException('Given stream resource is not opened in read and write mode');
}

Expand All @@ -59,14 +59,9 @@ public function __construct($stream, LoopInterface $loop = null, $readChunkSize
// Use unbuffered read operations on the underlying stream resource.
// Reading chunks from the stream may otherwise leave unread bytes in
// PHP's stream buffers which some event loop implementations do not
// trigger events on (edge triggered).
// This does not affect the default event loop implementation (level
// triggered), so we can ignore platforms not supporting this (HHVM).
// Pipe streams (such as STDIN) do not seem to require this and legacy
// PHP versions cause SEGFAULTs on unbuffered pipe streams, so skip this.
if (\function_exists('stream_set_read_buffer') && !$this->isLegacyPipe($stream)) {
\stream_set_read_buffer($stream, 0);
}
// trigger events on (edge triggered). This does not affect the default
// event loop implementation (level triggered).
\stream_set_read_buffer($stream, 0);

if ($buffer === null) {
$buffer = new WritableResourceStream($stream, $loop);
Expand All @@ -77,16 +72,14 @@ public function __construct($stream, LoopInterface $loop = null, $readChunkSize
$this->bufferSize = ($readChunkSize === null) ? 65536 : (int)$readChunkSize;
$this->buffer = $buffer;

$that = $this;

$this->buffer->on('error', function ($error) use ($that) {
$that->emit('error', array($error));
$this->buffer->on('error', function ($error) {
$this->emit('error', [$error]);
});

$this->buffer->on('close', array($this, 'close'));
$this->buffer->on('close', [$this, 'close']);

$this->buffer->on('drain', function () use ($that) {
$that->emit('drain');
$this->buffer->on('drain', function () {
$this->emit('drain');
});

$this->resume();
Expand All @@ -113,7 +106,7 @@ public function pause()
public function resume()
{
if (!$this->listening && $this->readable) {
$this->loop->addReadStream($this->stream, array($this, 'handleData'));
$this->loop->addReadStream($this->stream, [$this, 'handleData']);
$this->listening = true;
}
}
Expand Down Expand Up @@ -163,7 +156,7 @@ public function end($data = null)
$this->buffer->end($data);
}

public function pipe(WritableStreamInterface $dest, array $options = array())
public function pipe(WritableStreamInterface $dest, array $options = [])
{
return Util::pipe($this, $dest, $options);
}
Expand All @@ -187,41 +180,17 @@ public function handleData($stream)
\restore_error_handler();

if ($error !== null) {
$this->emit('error', array(new \RuntimeException('Unable to read from stream: ' . $error->getMessage(), 0, $error)));
$this->emit('error', [new \RuntimeException('Unable to read from stream: ' . $error->getMessage(), 0, $error)]);
$this->close();
return;
}

if ($data !== '') {
$this->emit('data', array($data));
$this->emit('data', [$data]);
} elseif (\feof($this->stream)) {
// no data read => we reached the end and close the stream
$this->emit('end');
$this->close();
}
}

/**
* Returns whether this is a pipe resource in a legacy environment
*
* This works around a legacy PHP bug (#61019) that was fixed in PHP 5.4.28+
* and PHP 5.5.12+ and newer.
*
* @param resource $resource
* @return bool
* @link https://github.com/reactphp/child-process/issues/40
*
* @codeCoverageIgnore
*/
private function isLegacyPipe($resource)
{
if (\PHP_VERSION_ID < 50428 || (\PHP_VERSION_ID >= 50500 && \PHP_VERSION_ID < 50512)) {
$meta = \stream_get_meta_data($resource);

if (isset($meta['stream_type']) && $meta['stream_type'] === 'STDIO') {
return true;
}
}
return false;
}
}
45 changes: 8 additions & 37 deletions src/ReadableResourceStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function __construct($stream, LoopInterface $loop = null, $readChunkSize

// ensure resource is opened for reading (fopen mode must contain "r" or "+")
$meta = \stream_get_meta_data($stream);
if (isset($meta['mode']) && $meta['mode'] !== '' && \strpos($meta['mode'], 'r') === \strpos($meta['mode'], '+')) {
if (\strpos($meta['mode'], 'r') === \strpos($meta['mode'], '+')) {
throw new InvalidArgumentException('Given stream resource is not opened in read mode');
}

Expand All @@ -61,14 +61,9 @@ public function __construct($stream, LoopInterface $loop = null, $readChunkSize
// Use unbuffered read operations on the underlying stream resource.
// Reading chunks from the stream may otherwise leave unread bytes in
// PHP's stream buffers which some event loop implementations do not
// trigger events on (edge triggered).
// This does not affect the default event loop implementation (level
// triggered), so we can ignore platforms not supporting this (HHVM).
// Pipe streams (such as STDIN) do not seem to require this and legacy
// PHP versions cause SEGFAULTs on unbuffered pipe streams, so skip this.
if (\function_exists('stream_set_read_buffer') && !$this->isLegacyPipe($stream)) {
\stream_set_read_buffer($stream, 0);
}
// trigger events on (edge triggered). This does not affect the default
// event loop implementation (level triggered).
\stream_set_read_buffer($stream, 0);

$this->stream = $stream;
$this->loop = $loop ?: Loop::get();
Expand All @@ -93,12 +88,12 @@ public function pause()
public function resume()
{
if (!$this->listening && !$this->closed) {
$this->loop->addReadStream($this->stream, array($this, 'handleData'));
$this->loop->addReadStream($this->stream, [$this, 'handleData']);
$this->listening = true;
}
}

public function pipe(WritableStreamInterface $dest, array $options = array())
public function pipe(WritableStreamInterface $dest, array $options = [])
{
return Util::pipe($this, $dest, $options);
}
Expand Down Expand Up @@ -139,41 +134,17 @@ public function handleData()
\restore_error_handler();

if ($error !== null) {
$this->emit('error', array(new \RuntimeException('Unable to read from stream: ' . $error->getMessage(), 0, $error)));
$this->emit('error', [new \RuntimeException('Unable to read from stream: ' . $error->getMessage(), 0, $error)]);
$this->close();
return;
}

if ($data !== '') {
$this->emit('data', array($data));
$this->emit('data', [$data]);
} elseif (\feof($this->stream)) {
// no data read => we reached the end and close the stream
$this->emit('end');
$this->close();
}
}

/**
* Returns whether this is a pipe resource in a legacy environment
*
* This works around a legacy PHP bug (#61019) that was fixed in PHP 5.4.28+
* and PHP 5.5.12+ and newer.
*
* @param resource $resource
* @return bool
* @link https://github.com/reactphp/child-process/issues/40
*
* @codeCoverageIgnore
*/
private function isLegacyPipe($resource)
{
if (\PHP_VERSION_ID < 50428 || (\PHP_VERSION_ID >= 50500 && \PHP_VERSION_ID < 50512)) {
$meta = \stream_get_meta_data($resource);

if (isset($meta['stream_type']) && $meta['stream_type'] === 'STDIO') {
return true;
}
}
return false;
}
}
4 changes: 2 additions & 2 deletions src/ReadableStreamInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ public function resume();
* source stream emits an `end` event. This can be disabled like this:
*
* ```php
* $source->pipe($dest, array('end' => false));
* $source->pipe($dest, ['end' => false]);
* ```
*
* Note that this only applies to the `end` event.
Expand Down Expand Up @@ -322,7 +322,7 @@ public function resume();
* @param array $options
* @return WritableStreamInterface $dest stream as-is
*/
public function pipe(WritableStreamInterface $dest, array $options = array());
public function pipe(WritableStreamInterface $dest, array $options = []);

/**
* Closes the stream (forcefully).
Expand Down
8 changes: 4 additions & 4 deletions src/ThroughStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
* });
* $through->on('data', $this->expectCallableOnceWith("[2, true]\n"));
*
* $through->write(array(2, true));
* $through->write([2, true]);
* ```
*
* The callback function is allowed to throw an `Exception`. In this case,
Expand Down Expand Up @@ -108,7 +108,7 @@ public function resume()
}
}

public function pipe(WritableStreamInterface $dest, array $options = array())
public function pipe(WritableStreamInterface $dest, array $options = [])
{
return Util::pipe($this, $dest, $options);
}
Expand All @@ -133,14 +133,14 @@ public function write($data)
try {
$data = \call_user_func($this->callback, $data);
} catch (\Exception $e) {
$this->emit('error', array($e));
$this->emit('error', [$e]);
$this->close();

return false;
}
}

$this->emit('data', array($data));
$this->emit('data', [$data]);

// emit drain event on next resume if currently paused (throttled)
if ($this->paused) {
Expand Down
Loading