Skip to content

Commit

Permalink
Require PHP 8.1 and use features (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski authored May 31, 2022
1 parent 4e14f0a commit cf1dda6
Show file tree
Hide file tree
Showing 17 changed files with 73 additions and 99 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ jobs:
fail-fast: false
matrix:
include:
- operating-system: 'ubuntu-latest'
php-version: '8.0'
composer-flags: '--ignore-platform-req=php'
- operating-system: 'ubuntu-latest'
php-version: '8.1'
composer-flags: '--ignore-platform-req=php'
Expand All @@ -40,7 +37,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: fiber-amphp/ext-fiber@master, uv-amphp/ext-uv@master, ev-beta, event, :xdebug
extensions: uv-amphp/ext-uv@master, ev-beta, event, :xdebug

- name: Get Composer cache directory
id: composer-cache
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ Different (strongly) opinionated libraries can be built on top of it and both Am
## Installation

It may surprise people to learn that the PHP standard library already has everything we need to write event-driven and non-blocking applications.
This package can be installed as a [Composer](https://getcomposer.org/) dependency on PHP 8 and later.
PHP 8.1 ships with fibers built-in, but users on PHP 8.0 can install [`ext-fiber`](https://github.com/amphp/ext-fiber) with almost identical behavior.
This package can be installed as a [Composer](https://getcomposer.org/) dependency on PHP 8.1 and later.

```bash
composer require revolt/event-loop
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
}
],
"require": {
"php": ">=8.0.7"
"php": ">=8.1"
},
"require-dev": {
"ext-json": "*",
Expand Down
6 changes: 3 additions & 3 deletions src/EventLoop/Driver/EvDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public static function isSupported(): bool
/** @var \EvWatcher[] */
private array $events = [];

private \Closure $ioCallback;
private readonly \Closure $ioCallback;

private \Closure $timerCallback;
private readonly \Closure $timerCallback;

private \Closure $signalCallback;
private readonly \Closure $signalCallback;

/** @var \EvSignal[] */
private array $signals = [];
Expand Down
6 changes: 3 additions & 3 deletions src/EventLoop/Driver/EventDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ public static function isSupported(): bool
private \EventBase $handle;
/** @var \Event[] */
private array $events = [];
private \Closure $ioCallback;
private \Closure $timerCallback;
private \Closure $signalCallback;
private readonly \Closure $ioCallback;
private readonly \Closure $timerCallback;
private readonly \Closure $signalCallback;
private array $signals = [];

public function __construct()
Expand Down
32 changes: 22 additions & 10 deletions src/EventLoop/Driver/StreamSelectDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ final class StreamSelectDriver extends AbstractDriver
/** @var StreamWritableCallback[][] */
private array $writeCallbacks = [];

private TimerQueue $timerQueue;
private readonly TimerQueue $timerQueue;

/** @var SignalCallback[][] */
private array $signalCallbacks = [];

/** @var \SplQueue<int> */
private \SplQueue $signalQueue;
private readonly \SplQueue $signalQueue;

private bool $signalHandling;

private \Closure $streamSelectErrorHandler;
private readonly \Closure $streamSelectErrorHandler;

private bool $streamSelectIgnoreResult = false;

Expand Down Expand Up @@ -166,12 +166,19 @@ protected function activate(array $callbacks): void
$this->timerQueue->insert($callback);
} elseif ($callback instanceof SignalCallback) {
if (!isset($this->signalCallbacks[$callback->signal])) {
if (!@\pcntl_signal($callback->signal, \Closure::fromCallable([$this, 'handleSignal']))) {
$message = "Failed to register signal handler";
if ($error = \error_get_last()) {
$message .= \sprintf("; Errno: %d; %s", $error["type"], $error["message"]);
}
throw new \Error($message);
\set_error_handler(static function (int $errno, string $errstr): bool {
throw new UnsupportedFeatureException(
\sprintf("Failed to register signal handler; Errno: %d; %s", $errno, $errstr)
);
});

// Avoid bug in Psalm handling of first-class callables by assigning to a temp variable.
$handler = $this->handleSignal(...);

try {
\pcntl_signal($callback->signal, $handler);
} finally {
\restore_error_handler();
}
}

Expand Down Expand Up @@ -209,7 +216,12 @@ protected function deactivate(DriverCallback $callback): void

if (empty($this->signalCallbacks[$callback->signal])) {
unset($this->signalCallbacks[$callback->signal]);
@\pcntl_signal($callback->signal, \SIG_DFL);
\set_error_handler(static fn () => true);
try {
\pcntl_signal($callback->signal, \SIG_DFL);
} finally {
\restore_error_handler();
}
}
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/EventLoop/Driver/TracingDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

final class TracingDriver implements Driver
{
private Driver $driver;
private readonly Driver $driver;

/** @var true[] */
private array $enabledCallbacks = [];
Expand Down
6 changes: 3 additions & 3 deletions src/EventLoop/Driver/UvDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ public static function isSupported(): bool
private array $callbacks = [];
/** @var resource[] */
private array $streams = [];
private \Closure $ioCallback;
private \Closure $timerCallback;
private \Closure $signalCallback;
private readonly \Closure $ioCallback;
private readonly \Closure $timerCallback;
private readonly \Closure $signalCallback;

public function __construct()
{
Expand Down
2 changes: 1 addition & 1 deletion src/EventLoop/FiberLocal.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private static function getFiberStorage(): \WeakMap
/**
* @param \Closure():T $initializer
*/
public function __construct(private \Closure $initializer)
public function __construct(private readonly \Closure $initializer)
{
}

Expand Down
43 changes: 8 additions & 35 deletions src/EventLoop/Internal/AbstractDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,6 @@
*/
abstract class AbstractDriver implements Driver
{
private static function checkFiberSupport(): void
{
if (!\class_exists(\Fiber::class, false)) {
if (\PHP_VERSION_ID < 80000) {
throw new \Error(
"revolt/event-loop requires fibers to be available. " .
"You're currently running PHP " . \PHP_VERSION . " without fiber support. " .
"Please upgrade to PHP 8.1 or upgrade to PHP 8.0 and install ext-fiber from https://github.com/amphp/ext-fiber."
);
}

if (\PHP_VERSION_ID < 80100) {
throw new \Error(
"revolt/event-loop requires fibers to be available. " .
"You're currently running PHP " . \PHP_VERSION . " without fiber support. " .
"Please upgrade to PHP 8.1 or install ext-fiber from https://github.com/amphp/ext-fiber."
);
}

throw new \Error(
"revolt/event-loop requires PHP 8.1 or ext-fiber. You are currently running PHP " . \PHP_VERSION . "."
);
}
}

/** @var string Next callback identifier. */
private string $nextId = "a";

Expand All @@ -66,17 +41,17 @@ private static function checkFiberSupport(): void
private ?\Closure $errorHandler = null;
private ?\Closure $interrupt = null;

private \Closure $interruptCallback;
private \Closure $queueCallback;
private \Closure $runCallback;
private readonly \Closure $interruptCallback;
private readonly \Closure $queueCallback;
private readonly \Closure $runCallback;

private \stdClass $internalSuspensionMarker;
private readonly \stdClass $internalSuspensionMarker;

/** @var \SplQueue<array{\Closure, array}> */
private \SplQueue $microtaskQueue;
private readonly \SplQueue $microtaskQueue;

/** @var \SplQueue<DriverCallback> */
private \SplQueue $callbackQueue;
private readonly \SplQueue $callbackQueue;

private bool $idle = false;
private bool $stopped = false;
Expand All @@ -85,8 +60,6 @@ private static function checkFiberSupport(): void

public function __construct()
{
self::checkFiberSupport();

$this->suspensions = new \WeakMap();

$this->internalSuspensionMarker = new \stdClass();
Expand All @@ -98,8 +71,8 @@ public function __construct()
$this->createErrorCallback();

/** @psalm-suppress InvalidArgument */
$this->interruptCallback = \Closure::fromCallable([$this, 'setInterrupt']);
$this->queueCallback = \Closure::fromCallable([$this, 'queue']);
$this->interruptCallback = $this->setInterrupt(...);
$this->queueCallback = $this->queue(...);
$this->runCallback = function () {
if ($this->fiber->isTerminated()) {
$this->createLoopFiber();
Expand Down
15 changes: 4 additions & 11 deletions src/EventLoop/Internal/DriverCallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,25 @@ abstract class DriverCallback

public bool $referenced = true;

public \Closure $closure;

public function __construct(
public string $id,
\Closure $closure
public readonly string $id,
public readonly \Closure $closure
) {
$this->closure = $closure;
}

/**
* @param string $property
*
* @psalm-return no-return
*/
public function __get(string $property): void
public function __get(string $property): never
{
throw new \Error("Unknown property '${property}'");
}

/**
* @param string $property
* @param mixed $value
*
* @psalm-return no-return
*/
public function __set(string $property, mixed $value): void
public function __set(string $property, mixed $value): never
{
throw new \Error("Unknown property '${property}'");
}
Expand Down
14 changes: 7 additions & 7 deletions src/EventLoop/Internal/DriverSuspension.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ final class DriverSuspension implements Suspension
private ?\Fiber $suspendedFiber = null;

/** @var \WeakReference<\Fiber>|null */
private ?\WeakReference $fiberRef;
private readonly ?\WeakReference $fiberRef;

private ?\FiberError $fiberError = null;

private \Closure $run;
private readonly \Closure $run;

private \Closure $queue;
private readonly \Closure $queue;

private \Closure $interrupt;
private readonly \Closure $interrupt;

private bool $pending = false;

private \WeakReference $suspensions;
private readonly \WeakReference $suspensions;

/**
* @param \Closure $run
Expand Down Expand Up @@ -59,7 +59,7 @@ public function resume(mixed $value = null): void
$fiber = $this->fiberRef?->get();

if ($fiber) {
($this->queue)(\Closure::fromCallable([$fiber, 'resume']), $value);
($this->queue)($fiber->resume(...), $value);
} else {
// Suspend event loop fiber to {main}.
($this->interrupt)(static fn () => $value);
Expand Down Expand Up @@ -139,7 +139,7 @@ public function throw(\Throwable $throwable): void
$fiber = $this->fiberRef?->get();

if ($fiber) {
($this->queue)(\Closure::fromCallable([$fiber, 'throw']), $throwable);
($this->queue)($fiber->throw(...), $throwable);
} else {
// Suspend event loop fiber to {main}.
($this->interrupt)(static fn () => throw $throwable);
Expand Down
2 changes: 1 addition & 1 deletion src/EventLoop/Internal/SignalCallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ final class SignalCallback extends DriverCallback
public function __construct(
string $id,
\Closure $closure,
public int $signal
public readonly int $signal
) {
parent::__construct($id, $closure);
}
Expand Down
2 changes: 1 addition & 1 deletion src/EventLoop/Internal/StreamCallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ abstract class StreamCallback extends DriverCallback
public function __construct(
string $id,
\Closure $closure,
public mixed $stream
public readonly mixed $stream
) {
parent::__construct($id, $closure);
}
Expand Down
4 changes: 2 additions & 2 deletions src/EventLoop/Internal/TimerCallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ final class TimerCallback extends DriverCallback
{
public function __construct(
string $id,
public float $interval,
public readonly float $interval,
\Closure $callback,
public float $expiration,
public bool $repeat = false
public readonly bool $repeat = false
) {
parent::__construct($id, $callback);
}
Expand Down
4 changes: 2 additions & 2 deletions src/EventLoop/InvalidCallbackError.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ public static function invalidIdentifier(string $callbackId): self
}

/** @var string */
private string $rawMessage;
private readonly string $rawMessage;

/** @var string */
private string $callbackId;
private readonly string $callbackId;

/** @var string[] */
private array $info = [];
Expand Down
Loading

0 comments on commit cf1dda6

Please sign in to comment.