{"id":13616351,"url":"https://github.com/reactphp/event-loop","last_synced_at":"2025-05-14T01:08:11.984Z","repository":{"id":3249867,"uuid":"4287598","full_name":"reactphp/event-loop","owner":"reactphp","description":"ReactPHP's core reactor event loop that libraries can use for evented I/O.","archived":false,"fork":false,"pushed_at":"2024-07-08T13:27:18.000Z","size":558,"stargazers_count":1249,"open_issues_count":4,"forks_count":126,"subscribers_count":49,"default_branch":"3.x","last_synced_at":"2024-10-29T15:04:44.510Z","etag":null,"topics":["event-loop","php","reactphp"],"latest_commit_sha":null,"homepage":"https://reactphp.org/event-loop/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reactphp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["reactphp","clue","WyriHaximus"],"open_collective":"reactphp"}},"created_at":"2012-05-10T17:30:32.000Z","updated_at":"2024-10-25T16:16:13.000Z","dependencies_parsed_at":"2024-01-15T08:53:38.743Z","dependency_job_id":"3b221cea-2dfc-4c3e-843c-2875ccb9843e","html_url":"https://github.com/reactphp/event-loop","commit_stats":{"total_commits":357,"total_committers":45,"mean_commits":7.933333333333334,"dds":0.7899159663865546,"last_synced_commit":"f2fb5a22568c4d29737d69208d1394ac47d77a38"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactphp%2Fevent-loop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactphp%2Fevent-loop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactphp%2Fevent-loop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactphp%2Fevent-loop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reactphp","download_url":"https://codeload.github.com/reactphp/event-loop/tar.gz/refs/heads/3.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247936155,"owners_count":21020978,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["event-loop","php","reactphp"],"created_at":"2024-08-01T20:01:27.346Z","updated_at":"2025-04-09T02:11:32.785Z","avatar_url":"https://github.com/reactphp.png","language":"PHP","readme":"# EventLoop\n\n[![CI status](https://github.com/reactphp/event-loop/actions/workflows/ci.yml/badge.svg)](https://github.com/reactphp/event-loop/actions)\n[![installs on Packagist](https://img.shields.io/packagist/dt/react/event-loop?color=blue\u0026label=installs%20on%20Packagist)](https://packagist.org/packages/react/event-loop)\n\n[ReactPHP](https://reactphp.org/)'s core reactor event loop that libraries can use for evented I/O.\n\n\u003e **Development version:** This branch contains the code for the upcoming v3 \n\u003e release. For the code of the current stable v1 release, check out the \n\u003e [`1.x` branch](https://github.com/reactphp/event-loop/tree/1.x).\n\u003e\n\u003e The upcoming v3 release will be the way forward for this package. However,\n\u003e we will still actively support v1 for those not yet on the latest version. \n\u003e See also [installation instructions](#install) for more details.\n\nIn order for async based libraries to be interoperable, they need to use the\nsame event loop. This component provides a common `LoopInterface` that any\nlibrary can target. This allows them to be used in the same loop, with one\nsingle [`run()`](#run) call that is controlled by the user.\n\n**Table of contents**\n\n* [Quickstart example](#quickstart-example)\n* [Usage](#usage)\n    * [Loop](#loop)\n        * [Loop methods](#loop-methods)\n        * [Loop autorun](#loop-autorun)\n        * [get()](#get)\n    * [Loop implementations](#loop-implementations)\n        * [StreamSelectLoop](#streamselectloop)\n        * [ExtEventLoop](#exteventloop)\n        * [ExtEvLoop](#extevloop)\n        * [ExtUvLoop](#extuvloop)\n    * [LoopInterface](#loopinterface)\n        * [run()](#run)\n        * [stop()](#stop)\n        * [addTimer()](#addtimer)\n        * [addPeriodicTimer()](#addperiodictimer)\n        * [cancelTimer()](#canceltimer)\n        * [futureTick()](#futuretick)\n        * [addSignal()](#addsignal)\n        * [removeSignal()](#removesignal)\n        * [addReadStream()](#addreadstream)\n        * [addWriteStream()](#addwritestream)\n        * [removeReadStream()](#removereadstream)\n        * [removeWriteStream()](#removewritestream)\n* [Install](#install)\n* [Tests](#tests)\n* [License](#license)\n* [More](#more)\n\n## Quickstart example\n\nHere is an async HTTP server built with just the event loop.\n\n```php\n\u003c?php\n\nuse React\\EventLoop\\Loop;\n\nrequire __DIR__ . '/vendor/autoload.php';\n\n$server = stream_socket_server('tcp://127.0.0.1:8080');\nstream_set_blocking($server, false);\n\nLoop::addReadStream($server, function ($server) {\n    $conn = stream_socket_accept($server);\n    $data = \"HTTP/1.1 200 OK\\r\\nContent-Length: 3\\r\\n\\r\\nHi\\n\";\n    Loop::addWriteStream($conn, function ($conn) use (\u0026$data) {\n        $written = fwrite($conn, $data);\n        if ($written === strlen($data)) {\n            fclose($conn);\n            Loop::removeWriteStream($conn);\n        } else {\n            $data = substr($data, $written);\n        }\n    });\n});\n\nLoop::addPeriodicTimer(5, function () {\n    $memory = memory_get_usage() / 1024;\n    $formatted = number_format($memory, 3).'K';\n    echo \"Current memory usage: {$formatted}\\n\";\n});\n```\n\nSee also the [examples](examples).\n\n## Usage\n\nTypical applications would use the [`Loop` class](#loop) to use the default\nevent loop like this:\n\n```php\nuse React\\EventLoop\\Loop;\n\n$timer = Loop::addPeriodicTimer(0.1, function () {\n    echo 'Tick' . PHP_EOL;\n});\n\nLoop::addTimer(1.0, function () use ($timer) {\n    Loop::cancelTimer($timer);\n    echo 'Done' . PHP_EOL;\n});\n```\n\nAs an alternative, you can also explicitly create an event loop instance at the\nbeginning, reuse it throughout your program and finally run it at the end of the\nprogram like this:\n\n```php\n$loop = React\\EventLoop\\Loop::get();\n\n$timer = $loop-\u003eaddPeriodicTimer(0.1, function () {\n    echo 'Tick' . PHP_EOL;\n});\n\n$loop-\u003eaddTimer(1.0, function () use ($loop, $timer) {\n    $loop-\u003ecancelTimer($timer);\n    echo 'Done' . PHP_EOL;\n});\n\n$loop-\u003erun();\n```\n\nWhile the former is more concise, the latter is more explicit.\nIn both cases, the program would perform the exact same steps.\n\n1. The event loop instance is created at the beginning of the program. This is\n   implicitly done the first time you call the [`Loop` class](#loop)\n   (or by manually instantiating any of the [loop implementations](#loop-implementations)).\n2. The event loop is used directly or passed as an instance to library and\n   application code. In this example, a periodic timer is registered with the\n   event loop which simply outputs `Tick` every fraction of a second until another\n   timer stops the periodic timer after a second.\n3. The event loop is run at the end of the program. This is automatically done\n   when using the [`Loop` class](#loop) or explicitly with a single [`run()`](#run)\n   call at the end of the program.\n\nAs of `v1.2.0`, we highly recommend using the [`Loop` class](#loop).\nThe explicit loop instructions are still valid and may still be useful in some\napplications, especially for a transition period towards the more concise style.\n\n### Loop\n\nThe `Loop` class exists as a convenient global accessor for the event loop.\n\n#### Loop methods\n\nThe `Loop` class provides all methods that exist on the [`LoopInterface`](#loopinterface)\nas static methods:\n\n* [run()](#run)\n* [stop()](#stop)\n* [addTimer()](#addtimer)\n* [addPeriodicTimer()](#addperiodictimer)\n* [cancelTimer()](#canceltimer)\n* [futureTick()](#futuretick)\n* [addSignal()](#addsignal)\n* [removeSignal()](#removesignal)\n* [addReadStream()](#addreadstream)\n* [addWriteStream()](#addwritestream)\n* [removeReadStream()](#removereadstream)\n* [removeWriteStream()](#removewritestream)\n\nIf you're working with the event loop in your application code, it's often\neasiest to directly interface with the static methods defined on the `Loop` class\nlike this:\n\n```php\nuse React\\EventLoop\\Loop;\n\n$timer = Loop::addPeriodicTimer(0.1, function () {\n    echo 'Tick' . PHP_EOL;\n});\n\nLoop::addTimer(1.0, function () use ($timer) {\n    Loop::cancelTimer($timer);\n    echo 'Done' . PHP_EOL;\n});\n```\n\nOn the other hand, if you're familiar with object-oriented programming (OOP) and\ndependency injection (DI), you may want to inject an event loop instance and\ninvoke instance methods on the `LoopInterface` like this:\n\n```php\nuse React\\EventLoop\\Loop;\nuse React\\EventLoop\\LoopInterface;\n\nclass Greeter\n{\n    private $loop;\n\n    public function __construct(LoopInterface $loop)\n    {\n        $this-\u003eloop = $loop;\n    }\n\n    public function greet(string $name)\n    {\n        $this-\u003eloop-\u003eaddTimer(1.0, function () use ($name) {\n            echo 'Hello ' . $name . '!' . PHP_EOL;\n        });\n    }\n}\n\n$greeter = new Greeter(Loop::get());\n$greeter-\u003egreet('Alice');\n$greeter-\u003egreet('Bob');\n```\n\nEach static method call will be forwarded as-is to the underlying event loop\ninstance by using the [`Loop::get()`](#get) call internally.\nSee [`LoopInterface`](#loopinterface) for more details about available methods.\n\n#### Loop autorun\n\nWhen using the `Loop` class, it will automatically execute the loop at the end of\nthe program. This means the following example will schedule a timer and will\nautomatically execute the program until the timer event fires:\n\n```php\nuse React\\EventLoop\\Loop;\n\nLoop::addTimer(1.0, function () {\n    echo 'Hello' . PHP_EOL;\n});\n```\n\nAs of `v1.2.0`, we highly recommend using the `Loop` class this way and omitting any\nexplicit [`run()`](#run) calls. For BC reasons, the explicit [`run()`](#run)\nmethod is still valid and may still be useful in some applications, especially\nfor a transition period towards the more concise style.\n\nIf you don't want the `Loop` to run automatically, you can either explicitly\n[`run()`](#run) or [`stop()`](#stop) it. This can be useful if you're using\na global exception handler like this:\n\n```php\nuse React\\EventLoop\\Loop;\n\nLoop::addTimer(10.0, function () {\n    echo 'Never happens';\n});\n\nset_exception_handler(function (Throwable $e) {\n    echo 'Error: ' . $e-\u003egetMessage() . PHP_EOL;\n    Loop::stop();\n});\n\nthrow new RuntimeException('Demo');\n```\n\n#### get()\n\nThe `get(): LoopInterface` method can be used to\nget the currently active event loop instance.\n\nThis method will always return the same event loop instance throughout the\nlifetime of your application.\n\n```php\nuse React\\EventLoop\\Loop;\nuse React\\EventLoop\\LoopInterface;\n\n$loop = Loop::get();\n\nassert($loop instanceof LoopInterface);\nassert($loop === Loop::get());\n```\n\nThis is particularly useful if you're using object-oriented programming (OOP)\nand dependency injection (DI). In this case, you may want to inject an event\nloop instance and invoke instance methods on the `LoopInterface` like this:\n\n```php\nuse React\\EventLoop\\Loop;\nuse React\\EventLoop\\LoopInterface;\n\nclass Greeter\n{\n    private $loop;\n\n    public function __construct(LoopInterface $loop)\n    {\n        $this-\u003eloop = $loop;\n    }\n\n    public function greet(string $name)\n    {\n        $this-\u003eloop-\u003eaddTimer(1.0, function () use ($name) {\n            echo 'Hello ' . $name . '!' . PHP_EOL;\n        });\n    }\n}\n\n$greeter = new Greeter(Loop::get());\n$greeter-\u003egreet('Alice');\n$greeter-\u003egreet('Bob');\n```\n\nSee [`LoopInterface`](#loopinterface) for more details about available methods.\n\n### Loop implementations\n\nIn addition to the [`LoopInterface`](#loopinterface), there are a number of\nevent loop implementations provided.\n\nAll of the event loops support these features:\n\n* File descriptor polling\n* One-off timers\n* Periodic timers\n* Deferred execution on future loop tick\n\nFor most consumers of this package, the underlying event loop implementation is\nan implementation detail.\nYou should use the [`Loop` class](#loop) to automatically create a new instance.\n\nAdvanced! If you explicitly need a certain event loop implementation, you can\nmanually instantiate one of the following classes.\nNote that you may have to install the required PHP extensions for the respective\nevent loop implementation first or they will throw a `BadMethodCallException` on creation.\n\n#### StreamSelectLoop\n\nA `stream_select()` based event loop.\n\nThis uses the [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php)\nfunction and is the only implementation that works out of the box with PHP.\n\nThis event loop works out of the box on any PHP version.\nThis means that no installation is required and this library works on all\nplatforms and supported PHP versions.\nAccordingly, the [`Loop` class](#loop) will use this event loop by default if\nyou do not install any of the event loop extensions listed below.\n\nUnder the hood, it does a simple `select` system call.\nThis system call is limited to the maximum file descriptor number of\n`FD_SETSIZE` (platform dependent, commonly 1024) and scales with `O(m)`\n(`m` being the maximum file descriptor number passed).\nThis means that you may run into issues when handling thousands of streams\nconcurrently and you may want to look into using one of the alternative\nevent loop implementations listed below in this case.\nIf your use case is among the many common use cases that involve handling only\ndozens or a few hundred streams at once, then this event loop implementation\nperforms really well.\n\nIf you want to use signal handling (see also [`addSignal()`](#addsignal) below),\nthis event loop implementation requires `ext-pcntl`.\nThis extension is only available for Unix-like platforms and does not support\nWindows.\nIt is commonly installed as part of many PHP distributions.\nIf this extension is missing (or you're running on Windows), signal handling is\nnot supported and throws a `BadMethodCallException` instead.\n\nThis event loop is known to rely on wall-clock time to schedule future timers\nwhen using any version before PHP 7.3, because a monotonic time source is\nonly available as of PHP 7.3 (`hrtime()`).\nWhile this does not affect many common use cases, this is an important\ndistinction for programs that rely on a high time precision or on systems\nthat are subject to discontinuous time adjustments (time jumps).\nThis means that if you schedule a timer to trigger in 30s on PHP \u003c 7.3 and\nthen adjust your system time forward by 20s, the timer may trigger in 10s.\nSee also [`addTimer()`](#addtimer) for more details.\n\n#### ExtEventLoop\n\nAn `ext-event` based event loop.\n\nThis uses the [`event` PECL extension](https://pecl.php.net/package/event),\nthat provides an interface to `libevent` library.\n`libevent` itself supports a number of system-specific backends (epoll, kqueue).\n\nThis loop is known to work with PHP 7.1 through PHP 8+.\n\n#### ExtEvLoop\n\nAn `ext-ev` based event loop.\n\nThis loop uses the [`ev` PECL extension](https://pecl.php.net/package/ev),\nthat provides an interface to `libev` library.\n`libev` itself supports a number of system-specific backends (epoll, kqueue).\n\n\nThis loop is known to work with PHP 7.1 through PHP 8+.\n\n#### ExtUvLoop\n\nAn `ext-uv` based event loop.\n\nThis loop uses the [`uv` PECL extension](https://pecl.php.net/package/uv),\nthat provides an interface to `libuv` library.\n`libuv` itself supports a number of system-specific backends (epoll, kqueue).\n\nThis loop is known to work with PHP 7.1 through PHP 8+.\n\n### LoopInterface\n\n#### run()\n\nThe `run(): void` method can be used to\nrun the event loop until there are no more tasks to perform.\n\nFor many applications, this method is the only directly visible\ninvocation on the event loop.\nAs a rule of thumb, it is usually recommended to attach everything to the\nsame loop instance and then run the loop once at the bottom end of the\napplication.\n\n```php\n$loop-\u003erun();\n```\n\nThis method will keep the loop running until there are no more tasks\nto perform. In other words: This method will block until the last\ntimer, stream and/or signal has been removed.\n\nLikewise, it is imperative to ensure the application actually invokes\nthis method once. Adding listeners to the loop and missing to actually\nrun it will result in the application exiting without actually waiting\nfor any of the attached listeners.\n\nThis method MUST NOT be called while the loop is already running.\nThis method MAY be called more than once after it has explicitly been\n[`stop()`ped](#stop) or after it automatically stopped because it\npreviously did no longer have anything to do.\n\n#### stop()\n\nThe `stop(): void` method can be used to\ninstruct a running event loop to stop.\n\nThis method is considered advanced usage and should be used with care.\nAs a rule of thumb, it is usually recommended to let the loop stop\nonly automatically when it no longer has anything to do.\n\nThis method can be used to explicitly instruct the event loop to stop:\n\n```php\n$loop-\u003eaddTimer(3.0, function () use ($loop) {\n    $loop-\u003estop();\n});\n```\n\nCalling this method on a loop instance that is not currently running or\non a loop instance that has already been stopped has no effect.\n\n#### addTimer()\n\nThe `addTimer(float $interval, callable $callback): TimerInterface` method can be used to\nenqueue a callback to be invoked once after the given interval.\n\nThe second parameter MUST be a timer callback function that accepts\nthe timer instance as its only parameter.\nIf you don't use the timer instance inside your timer callback function\nyou MAY use a function which has no parameters at all.\n\nThe timer callback function MUST NOT throw an `Exception`.\nThe return value of the timer callback function will be ignored and has\nno effect, so for performance reasons you're recommended to not return\nany excessive data structures.\n\nThis method returns a timer instance. The same timer instance will also be \npassed into the timer callback function as described above.\nYou can invoke [`cancelTimer`](#canceltimer) to cancel a pending timer.\nUnlike [`addPeriodicTimer()`](#addperiodictimer), this method will ensure\nthe callback will be invoked only once after the given interval.\n\n```php\n$loop-\u003eaddTimer(0.8, function () {\n    echo 'world!' . PHP_EOL;\n});\n\n$loop-\u003eaddTimer(0.3, function () {\n    echo 'hello ';\n});\n```\n\nSee also [example #1](examples).\n\nIf you want to access any variables within your callback function, you\ncan bind arbitrary data to a callback closure like this:\n\n```php\nfunction hello($name, LoopInterface $loop)\n{\n    $loop-\u003eaddTimer(1.0, function () use ($name) {\n        echo \"hello $name\\n\";\n    });\n}\n\nhello('Tester', $loop);\n```\n\nThis interface does not enforce any particular timer resolution, so\nspecial care may have to be taken if you rely on very high precision with\nmillisecond accuracy or below. Event loop implementations SHOULD work on\na best effort basis and SHOULD provide at least millisecond accuracy\nunless otherwise noted. Many existing event loop implementations are\nknown to provide microsecond accuracy, but it's generally not recommended\nto rely on this high precision.\n\nSimilarly, the execution order of timers scheduled to execute at the\nsame time (within its possible accuracy) is not guaranteed.\n\nThis interface suggests that event loop implementations SHOULD use a\nmonotonic time source if available. Given that a monotonic time source is\nonly available as of PHP 7.3 by default, event loop implementations MAY\nfall back to using wall-clock time.\nWhile this does not affect many common use cases, this is an important\ndistinction for programs that rely on a high time precision or on systems\nthat are subject to discontinuous time adjustments (time jumps).\nThis means that if you schedule a timer to trigger in 30s and then adjust\nyour system time forward by 20s, the timer SHOULD still trigger in 30s.\nSee also [event loop implementations](#loop-implementations) for more details.\n\n#### addPeriodicTimer()\n\nThe `addPeriodicTimer(float $interval, callable $callback): TimerInterface` method can be used to\nenqueue a callback to be invoked repeatedly after the given interval.\n\nThe second parameter MUST be a timer callback function that accepts\nthe timer instance as its only parameter.\nIf you don't use the timer instance inside your timer callback function\nyou MAY use a function which has no parameters at all.\n\nThe timer callback function MUST NOT throw an `Exception`.\nThe return value of the timer callback function will be ignored and has\nno effect, so for performance reasons you're recommended to not return\nany excessive data structures.\n\nThis method returns a timer instance. The same timer instance will also be \npassed into the timer callback function as described above.\nUnlike [`addTimer()`](#addtimer), this method will ensure the callback \nwill be invoked infinitely after the given interval or until you invoke \n[`cancelTimer`](#canceltimer).\n\n```php\n$timer = $loop-\u003eaddPeriodicTimer(0.1, function () {\n    echo 'tick!' . PHP_EOL;\n});\n\n$loop-\u003eaddTimer(1.0, function () use ($loop, $timer) {\n    $loop-\u003ecancelTimer($timer);\n    echo 'Done' . PHP_EOL;\n});\n```\n\nSee also [example #2](examples).\n\nIf you want to limit the number of executions, you can bind\narbitrary data to a callback closure like this:\n\n```php\nfunction hello($name, LoopInterface $loop)\n{\n    $n = 3;\n    $loop-\u003eaddPeriodicTimer(1.0, function ($timer) use ($name, $loop, \u0026$n) {\n        if ($n \u003e 0) {\n            --$n;\n            echo \"hello $name\\n\";\n        } else {\n            $loop-\u003ecancelTimer($timer);\n        }\n    });\n}\n\nhello('Tester', $loop);\n```\n\nThis interface does not enforce any particular timer resolution, so\nspecial care may have to be taken if you rely on very high precision with\nmillisecond accuracy or below. Event loop implementations SHOULD work on\na best effort basis and SHOULD provide at least millisecond accuracy\nunless otherwise noted. Many existing event loop implementations are\nknown to provide microsecond accuracy, but it's generally not recommended\nto rely on this high precision.\n\nSimilarly, the execution order of timers scheduled to execute at the\nsame time (within its possible accuracy) is not guaranteed.\n\nThis interface suggests that event loop implementations SHOULD use a\nmonotonic time source if available. Given that a monotonic time source is\nonly available as of PHP 7.3 by default, event loop implementations MAY\nfall back to using wall-clock time.\nWhile this does not affect many common use cases, this is an important\ndistinction for programs that rely on a high time precision or on systems\nthat are subject to discontinuous time adjustments (time jumps).\nThis means that if you schedule a timer to trigger in 30s and then adjust\nyour system time forward by 20s, the timer SHOULD still trigger in 30s.\nSee also [event loop implementations](#loop-implementations) for more details.\n\nAdditionally, periodic timers may be subject to timer drift due to\nre-scheduling after each invocation. As such, it's generally not\nrecommended to rely on this for high precision intervals with millisecond\naccuracy or below.\n\n#### cancelTimer()\n\nThe `cancelTimer(TimerInterface $timer): void` method can be used to\ncancel a pending timer.\n\nSee also [`addPeriodicTimer()`](#addperiodictimer) and [example #2](examples).\n\nCalling this method on a timer instance that has not been added to this\nloop instance or on a timer that has already been cancelled has no effect.\n\n#### futureTick()\n\nThe `futureTick(callable $listener): void` method can be used to\nschedule a callback to be invoked on a future tick of the event loop.\n\nThis works very much similar to timers with an interval of zero seconds,\nbut does not require the overhead of scheduling a timer queue.\n\nThe tick callback function MUST be able to accept zero parameters.\n\nThe tick callback function MUST NOT throw an `Exception`.\nThe return value of the tick callback function will be ignored and has\nno effect, so for performance reasons you're recommended to not return\nany excessive data structures.\n\nIf you want to access any variables within your callback function, you\ncan bind arbitrary data to a callback closure like this:\n\n```php\nfunction hello($name, LoopInterface $loop)\n{\n    $loop-\u003efutureTick(function () use ($name) {\n        echo \"hello $name\\n\";\n    });\n}\n\nhello('Tester', $loop);\n```\n\nUnlike timers, tick callbacks are guaranteed to be executed in the order\nthey are enqueued.\nAlso, once a callback is enqueued, there's no way to cancel this operation.\n\nThis is often used to break down bigger tasks into smaller steps (a form\nof cooperative multitasking).\n\n```php\n$loop-\u003efutureTick(function () {\n    echo 'b';\n});\n$loop-\u003efutureTick(function () {\n    echo 'c';\n});\necho 'a';\n```\n\nSee also [example #3](examples).\n\n#### addSignal()\n\nThe `addSignal(int $signal, callable $listener): void` method can be used to\nregister a listener to be notified when a signal has been caught by this process.\n\nThis is useful to catch user interrupt signals or shutdown signals from\ntools like `supervisor` or `systemd`.\n\nThe second parameter MUST be a listener callback function that accepts\nthe signal as its only parameter.\nIf you don't use the signal inside your listener callback function\nyou MAY use a function which has no parameters at all.\n\nThe listener callback function MUST NOT throw an `Exception`.\nThe return value of the listener callback function will be ignored and has\nno effect, so for performance reasons you're recommended to not return\nany excessive data structures.\n\n```php\n$loop-\u003eaddSignal(SIGINT, function (int $signal) {\n    echo 'Caught user interrupt signal' . PHP_EOL;\n});\n```\n\nSee also [example #4](examples).\n\nSignaling is only available on Unix-like platforms, Windows isn't\nsupported due to operating system limitations.\nThis method may throw a `BadMethodCallException` if signals aren't\nsupported on this platform, for example when required extensions are\nmissing.\n\n**Note: A listener can only be added once to the same signal, any\nattempts to add it more than once will be ignored.**\n\n#### removeSignal()\n\nThe `removeSignal(int $signal, callable $listener): void` method can be used to\nremove a previously added signal listener.\n\n```php\n$loop-\u003eremoveSignal(SIGINT, $listener);\n```\n\nAny attempts to remove listeners that aren't registered will be ignored.\n\n#### addReadStream()\n\n\u003e Advanced! Note that this low-level API is considered advanced usage.\n  Most use cases should probably use the higher-level\n  [readable Stream API](https://github.com/reactphp/stream#readablestreaminterface)\n  instead.\n\nThe `addReadStream(resource $stream, callable $callback): void` method can be used to\nregister a listener to be notified when a stream is ready to read.\n\nThe first parameter MUST be a valid stream resource that supports\nchecking whether it is ready to read by this loop implementation.\nA single stream resource MUST NOT be added more than once.\nInstead, either call [`removeReadStream()`](#removereadstream) first or\nreact to this event with a single listener and then dispatch from this\nlistener. This method MAY throw an `Exception` if the given resource type\nis not supported by this loop implementation.\n\nThe second parameter MUST be a listener callback function that accepts\nthe stream resource as its only parameter.\nIf you don't use the stream resource inside your listener callback function\nyou MAY use a function which has no parameters at all.\n\nThe listener callback function MUST NOT throw an `Exception`.\nThe return value of the listener callback function will be ignored and has\nno effect, so for performance reasons you're recommended to not return\nany excessive data structures.\n\nIf you want to access any variables within your callback function, you\ncan bind arbitrary data to a callback closure like this:\n\n```php\n$loop-\u003eaddReadStream($stream, function ($stream) use ($name) {\n    echo $name . ' said: ' . fread($stream);\n});\n```\n\nSee also [example #11](examples).\n\nYou can invoke [`removeReadStream()`](#removereadstream) to remove the\nread event listener for this stream.\n\nThe execution order of listeners when multiple streams become ready at\nthe same time is not guaranteed.\n\nSome event loop implementations are known to only trigger the listener if\nthe stream *becomes* readable (edge-triggered) and may not trigger if the\nstream has already been readable from the beginning.\nThis also implies that a stream may not be recognized as readable when data\nis still left in PHP's internal stream buffers.\nAs such, it's recommended to use `stream_set_read_buffer($stream, 0);`\nto disable PHP's internal read buffer in this case.\n\n#### addWriteStream()\n\n\u003e Advanced! Note that this low-level API is considered advanced usage.\n  Most use cases should probably use the higher-level\n  [writable Stream API](https://github.com/reactphp/stream#writablestreaminterface)\n  instead.\n\nThe `addWriteStream(resource $stream, callable $callback): void` method can be used to\nregister a listener to be notified when a stream is ready to write.\n\nThe first parameter MUST be a valid stream resource that supports\nchecking whether it is ready to write by this loop implementation.\nA single stream resource MUST NOT be added more than once.\nInstead, either call [`removeWriteStream()`](#removewritestream) first or\nreact to this event with a single listener and then dispatch from this\nlistener. This method MAY throw an `Exception` if the given resource type\nis not supported by this loop implementation.\n\nThe second parameter MUST be a listener callback function that accepts\nthe stream resource as its only parameter.\nIf you don't use the stream resource inside your listener callback function\nyou MAY use a function which has no parameters at all.\n\nThe listener callback function MUST NOT throw an `Exception`.\nThe return value of the listener callback function will be ignored and has\nno effect, so for performance reasons you're recommended to not return\nany excessive data structures.\n\nIf you want to access any variables within your callback function, you\ncan bind arbitrary data to a callback closure like this:\n\n```php\n$loop-\u003eaddWriteStream($stream, function ($stream) use ($name) {\n    fwrite($stream, 'Hello ' . $name);\n});\n```\n\nSee also [example #12](examples).\n\nYou can invoke [`removeWriteStream()`](#removewritestream) to remove the\nwrite event listener for this stream.\n\nThe execution order of listeners when multiple streams become ready at\nthe same time is not guaranteed.\n\n#### removeReadStream()\n\nThe `removeReadStream(resource $stream): void` method can be used to\nremove the read event listener for the given stream.\n\nRemoving a stream from the loop that has already been removed or trying\nto remove a stream that was never added or is invalid has no effect.\n\n#### removeWriteStream()\n\nThe `removeWriteStream(resource $stream): void` method can be used to\nremove the write event listener for the given stream.\n\nRemoving a stream from the loop that has already been removed or trying\nto remove a stream that was never added or is invalid has no effect.\n\n## Install\n\nThe recommended way to install this library is [through Composer](https://getcomposer.org/).\n[New to Composer?](https://getcomposer.org/doc/00-intro.md)\n\nOnce released, this project will follow [SemVer](https://semver.org/).\nAt the moment, this will install the latest development version:\n\n```bash\ncomposer require react/event-loop:^3@dev\n```\n\nSee also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.\n\nThis project aims to run on any platform and thus does not require any PHP\nextensions and supports running on PHP 7.1 through current PHP 8+.\nIt's *highly recommended to use the latest supported PHP version* for this project.\n\nInstalling any of the event loop extensions is suggested, but entirely optional.\nSee also [event loop implementations](#loop-implementations) for more details.\n\n## Tests\n\nTo run the test suite, you first need to clone this repo and then install all\ndependencies [through Composer](https://getcomposer.org/):\n\n```bash\ncomposer install\n```\n\nTo run the test suite, go to the project root and run:\n\n```bash\nvendor/bin/phpunit\n```\n\n## License\n\nMIT, see [LICENSE file](LICENSE).\n\n## More\n\n* See our [Stream component](https://github.com/reactphp/stream) for more\n  information on how streams are used in real-world applications.\n* See our [users wiki](https://github.com/reactphp/react/wiki/Users) and the\n  [dependents on Packagist](https://packagist.org/packages/react/event-loop/dependents)\n  for a list of packages that use the EventLoop in real-world applications.\n","funding_links":["https://github.com/sponsors/reactphp","https://github.com/sponsors/clue","https://github.com/sponsors/WyriHaximus","https://opencollective.com/reactphp"],"categories":["PHP"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactphp%2Fevent-loop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freactphp%2Fevent-loop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactphp%2Fevent-loop/lists"}