diff --git a/README.md b/README.md index d98e4c73..e9531a50 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,25 @@ For the code of the current stable 0.4.x release, checkout the * [Quickstart example](#quickstart-example) * [Usage](#usage) -* [Loop implementations](#loop-implementations) + * [Factory](#factory) + * [create()](#create) + * [Loop implementations](#loop-implementations) + * [StreamSelectLoop](#streamselectloop) + * [LibEventLoop](#libeventloop) + * [LibEvLoop](#libevloop) + * [ExtEventLoop](#exteventloop) + * [LoopInterface](#loopinterface) + * [addtimer()](#addtimer) + * [addPeriodicTimer()](#addperiodictimer) + * [cancelTimer()](#canceltimer) + * [isTimerActive()](#istimeractive) + * [futureTick()](#futuretick) + * [addSignal()](#addsignal) + * [removeSignal()](#removesignal) + * [addReadStream()](#addreadstream) + * [addWriteStream()](#addwritestream) + * [removeReadStream()](#removereadstream) + * [removeWriteStream()](#removewritestream) * [Install](#install) * [Tests](#tests) * [License](#license) @@ -94,49 +112,115 @@ $loop->run(); purposes. 3. The loop is run with a single `$loop->run()` call at the end of the program. -## Factory +### Factory The `Factory` class exists as a convenient way to pick the best available -[loop implementation](#loop-implementations). +[event loop implementation](#loop-implementations). -The `create(): LoopInterface` method can be used to create a new loop +#### create() + +The `create(): LoopInterface` method can be used to create a new event loop instance: ```php $loop = React\EventLoop\Factory::create(); ``` -This method always returns an instance implementing `LoopInterface`, -the actual loop implementation is an implementation detail. +This method always returns an instance implementing [`LoopInterface`](#loopinterface), +the actual [event loop implementation](#loop-implementations) is an implementation detail. This method should usually only be called once at the beginning of the program. -## Loop implementations - -In addition to the interface there are the following implementations provided: - -* `StreamSelectLoop`: This is the only implementation which works out of the - box with PHP. It does a simple `select` system call. It's not the most - performant of loops, but still does the job quite well. - -* `LibEventLoop`: This uses the `libevent` pecl extension. `libevent` itself - supports a number of system-specific backends (epoll, kqueue). +### Loop implementations -* `LibEvLoop`: This uses the `libev` pecl extension - ([github](https://github.com/m4rw3r/php-libev)). It supports the same - backends as libevent. +In addition to the [`LoopInterface`](#loopinterface), there are a number of +event loop implementations provided. -* `ExtEventLoop`: This uses the `event` pecl extension. It supports the same - backends as libevent. - -All of the loops support these features: +All of the event loops support these features: * File descriptor polling * One-off timers * Periodic timers * Deferred execution on future loop tick -### addTimer() +For most consumers of this package, the underlying event loop implementation is +an implementation detail. +You should use the [`Factory`](#factory) to automatically create a new instance. + +Advanced! If you explicitly need a certain event loop implementation, you can +manually instantiate one of the following classes. +Note that you may have to install the required PHP extensions for the respective +event loop implementation first or this may result in a fatal error. + +#### StreamSelectLoop + +A `stream_select()` based event loop. + +This uses the [`stream_select()`](http://php.net/manual/en/function.stream-select.php) +function and is the only implementation which works out of the box with PHP. + +This event loop works out of the box on PHP 5.4 through PHP 7+ and HHVM. +This means that no installation is required and this library works on all +platforms and supported PHP versions. +Accordingly, the [`Factory`](#factory) will use this event loop by default if +you do not install any of the event loop extensions listed below. + +Under the hood, it does a simple `select` system call. +This system call is limited to the maximum file descriptor number of +`FD_SETSIZE` (platform dependent, commonly 1024) and scales with `O(m)` +(`m` being the maximum file descriptor number passed). +This means that you may run into issues when handling thousands of streams +concurrently and you may want to look into using one of the alternative +event loop implementations listed below in this case. +If your use case is among the many common use cases that involve handling only +dozens or a few hundred streams at once, then this event loop implementation +performs really well. + +If you want to use signal handling (see also [`addSignal()`](#addsignal) below), +this event loop implementation requires `ext-pcntl`. +This extension is only available for Unix-like platforms and does not support +Windows. +It is commonly installed as part of many PHP distributions. +If this extension is missing (or you're running on Windows), signal handling is +not supported and throws a `BadMethodCallException` instead. + +#### LibEventLoop + +An `ext-libevent` based event loop. + +This uses the [`libevent` PECL extension](https://pecl.php.net/package/libevent). +`libevent` itself supports a number of system-specific backends (epoll, kqueue). + +This event loop does only work with PHP 5. +An [unofficial update](https://github.com/php/pecl-event-libevent/pull/2) for +PHP 7 does exist, but it is known to cause regular crashes due to `SEGFAULT`s. +To reiterate: Using this event loop on PHP 7 is not recommended. +Accordingly, the [`Factory`](#factory) will not try to use this event loop on +PHP 7. + +#### LibEvLoop + +An `ext-libev` based event loop. + +This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev). +It supports the same backends as libevent. + +This loop does only work with PHP 5. +An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8) +to happen any time soon. + +#### ExtEventLoop + +An `ext-event` based event loop. + +This uses the [`event` PECL extension](https://pecl.php.net/package/event). +It supports the same backends as libevent. + +This loop is known to work with PHP 5.4 through PHP 7+. + +### LoopInterface + +#### addTimer() The `addTimer(float $interval, callable $callback): TimerInterface` method can be used to enqueue a callback to be invoked once after the given interval. @@ -183,7 +267,7 @@ hello('Tester', $loop); The execution order of timers scheduled to execute at the same time is not guaranteed. -### addPeriodicTimer() +#### addPeriodicTimer() The `addPeriodicTimer(float $interval, callable $callback): TimerInterface` method can be used to enqueue a callback to be invoked repeatedly after the given interval. @@ -237,7 +321,7 @@ hello('Tester', $loop); The execution order of timers scheduled to execute at the same time is not guaranteed. -### cancelTimer() +#### cancelTimer() The `cancelTimer(TimerInterface $timer): void` method can be used to cancel a pending timer. @@ -252,7 +336,7 @@ Calling this method on a timer instance that has not been added to this loop instance or on a timer that is not "active" (or has already been cancelled) has no effect. -### isTimerActive() +#### isTimerActive() The `isTimerActive(TimerInterface $timer): bool` method can be used to check if a given timer is active. @@ -262,7 +346,7 @@ via [`addTimer()`](#addtimer) or [`addPeriodicTimer()`](#addperiodictimer) and has not been cancelled via [`cancelTimer()`](#canceltimer) and is not a non-periodic timer that has already been triggered after its interval. -### futureTick() +#### futureTick() The `futureTick(callable $listener): void` method can be used to schedule a callback to be invoked on a future tick of the event loop. @@ -310,7 +394,7 @@ echo 'a'; See also [example #3](examples). -### addSignal() +#### addSignal() The `addSignal(int $signal, callable $listener): void` method can be used to register a listener to be notified when a signal has been caught by this process. @@ -344,7 +428,7 @@ missing. **Note: A listener can only be added once to the same signal, any attempts to add it more then once will be ignored.** -### removeSignal() +#### removeSignal() The `removeSignal(int $signal, callable $listener): void` method can be used to remove a previously added signal listener. @@ -355,7 +439,7 @@ $loop->removeSignal(SIGINT, $listener); Any attempts to remove listeners that aren't registered will be ignored. -### addReadStream() +#### addReadStream() > Advanced! Note that this low-level API is considered advanced usage. Most use cases should probably use the higher-level @@ -398,7 +482,7 @@ read event listener for this stream. The execution order of listeners when multiple streams become ready at the same time is not guaranteed. -### addWriteStream() +#### addWriteStream() > Advanced! Note that this low-level API is considered advanced usage. Most use cases should probably use the higher-level @@ -441,7 +525,7 @@ write event listener for this stream. The execution order of listeners when multiple streams become ready at the same time is not guaranteed. -### removeReadStream() +#### removeReadStream() The `removeReadStream(resource $stream): void` method can be used to remove the read event listener for the given stream. @@ -449,7 +533,7 @@ remove the read event listener for the given stream. Removing a stream from the loop that has already been removed or trying to remove a stream that was never added or is invalid has no effect. -### removeWriteStream() +#### removeWriteStream() The `removeWriteStream(resource $stream): void` method can be used to remove the write event listener for the given stream. @@ -468,6 +552,14 @@ This will install the latest supported version: $ composer require react/event-loop ``` +This project aims to run on any platform and thus does not require any PHP +extensions and supports running on legacy PHP 5.4 through current PHP 7+ and +HHVM. +It's *highly recommended to use PHP 7+* for this project. + +Installing any of the event loop extensions is suggested, but entirely optional. +See also [event loop implementations](#loop-implementations) for more details. + ## Tests To run the test suite, you first need to clone this repo and then install all diff --git a/src/ExtEventLoop.php b/src/ExtEventLoop.php index 05653c6e..73e7e97c 100644 --- a/src/ExtEventLoop.php +++ b/src/ExtEventLoop.php @@ -11,7 +11,14 @@ use SplObjectStorage; /** - * An ext-event based event-loop. + * An `ext-event` based event loop. + * + * This uses the [`event` PECL extension](https://pecl.php.net/package/event). + * It supports the same backends as libevent. + * + * This loop is known to work with PHP 5.4 through PHP 7+. + * + * @link https://pecl.php.net/package/event */ class ExtEventLoop implements LoopInterface { diff --git a/src/Factory.php b/src/Factory.php index 7c87180c..0e868358 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -3,19 +3,19 @@ namespace React\EventLoop; /** - * The `Factory` class exists as a convenient way to pick the best available loop implementation. + * The `Factory` class exists as a convenient way to pick the best available event loop implementation. */ class Factory { /** - * Creates a new loop instance + * Creates a new event loop instance * * ```php * $loop = React\EventLoop\Factory::create(); * ``` * * This method always returns an instance implementing `LoopInterface`, - * the actual loop implementation is an implementation detail. + * the actual event loop implementation is an implementation detail. * * This method should usually only be called once at the beginning of the program. * diff --git a/src/LibEvLoop.php b/src/LibEvLoop.php index 47701118..640c7da7 100644 --- a/src/LibEvLoop.php +++ b/src/LibEvLoop.php @@ -12,6 +12,15 @@ use SplObjectStorage; /** + * An `ext-libev` based event loop. + * + * This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev). + * It supports the same backends as libevent. + * + * This loop does only work with PHP 5. + * An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8) + * to happen any time soon. + * * @see https://github.com/m4rw3r/php-libev * @see https://gist.github.com/1688204 */ diff --git a/src/LibEventLoop.php b/src/LibEventLoop.php index 2e5a6c80..94cdbb01 100644 --- a/src/LibEventLoop.php +++ b/src/LibEventLoop.php @@ -10,7 +10,19 @@ use SplObjectStorage; /** - * An ext-libevent based event-loop. + * An `ext-libevent` based event loop. + * + * This uses the [`libevent` PECL extension](https://pecl.php.net/package/libevent). + * `libevent` itself supports a number of system-specific backends (epoll, kqueue). + * + * This event loop does only work with PHP 5. + * An [unofficial update](https://github.com/php/pecl-event-libevent/pull/2) for + * PHP 7 does exist, but it is known to cause regular crashes due to `SEGFAULT`s. + * To reiterate: Using this event loop on PHP 7 is not recommended. + * Accordingly, the [`Factory`](#factory) will not try to use this event loop on + * PHP 7. + * + * @link https://pecl.php.net/package/libevent */ class LibEventLoop implements LoopInterface { diff --git a/src/StreamSelectLoop.php b/src/StreamSelectLoop.php index 1cf6d1a3..af46ea23 100644 --- a/src/StreamSelectLoop.php +++ b/src/StreamSelectLoop.php @@ -9,7 +9,37 @@ use React\EventLoop\Timer\Timers; /** - * A stream_select() based event-loop. + * A `stream_select()` based event loop. + * + * This uses the [`stream_select()`](http://php.net/manual/en/function.stream-select.php) + * function and is the only implementation which works out of the box with PHP. + * + * This event loop works out of the box on PHP 5.4 through PHP 7+ and HHVM. + * This means that no installation is required and this library works on all + * platforms and supported PHP versions. + * Accordingly, the [`Factory`](#factory) will use this event loop by default if + * you do not install any of the event loop extensions listed below. + * + * Under the hood, it does a simple `select` system call. + * This system call is limited to the maximum file descriptor number of + * `FD_SETSIZE` (platform dependent, commonly 1024) and scales with `O(m)` + * (`m` being the maximum file descriptor number passed). + * This means that you may run into issues when handling thousands of streams + * concurrently and you may want to look into using one of the alternative + * event loop implementations listed below in this case. + * If your use case is among the many common use cases that involve handling only + * dozens or a few hundred streams at once, then this event loop implementation + * performs really well. + * + * If you want to use signal handling (see also [`addSignal()`](#addsignal) below), + * this event loop implementation requires `ext-pcntl`. + * This extension is only available for Unix-like platforms and does not support + * Windows. + * It is commonly installed as part of many PHP distributions. + * If this extension is missing (or you're running on Windows), signal handling is + * not supported and throws a `BadMethodCallException` instead. + * + * @link http://php.net/manual/en/function.stream-select.php */ class StreamSelectLoop implements LoopInterface {