Основной цикл событий реактора ReactPHP, который библиотеки могут использовать для событийного ввода-вывода.
Версия для разработки: эта ветка содержит код для предстоящего выпуска v3. Код текущей стабильной версии v1 можно найти в ветке
1.x
Предстоящий выпуск v3 станет шагом вперед для этого пакета. Тем не менее, мы по-прежнему будем активно поддерживать версию 1 для тех, кто еще не использует последнюю версию. Дополнительную информацию см. также в инструкциях по установке.
Чтобы асинхронные библиотеки были совместимыми, им необходимо использовать один и тот же цикл событий. Этот компонент предоставляет общий LoopInterface
, на который может ориентироваться любая библиотека. Это позволяет использовать их в одном цикле с одним вызовом run()
, которым управляет пользователь.
Оглавление
Пример быстрого старта
Использование
бегать()
останавливаться()
добавитьТаймер()
добавитьпериодическийтаймер()
отменитьТаймер()
будущееТик()
добавитьСигнал()
удалитьСигнал()
добавитьReadStream()
добавитьWriteStream()
удалитьReadStream()
удалитьWriteStream()
StreamSelectLoop
ExtEventLoop
Экстевлуп
ExtUvLoop
Методы цикла
Цикл автозапуска
получать()
Петля
Реализации цикла
Циклический интерфейс
Установить
Тесты
Лицензия
Более
Вот асинхронный HTTP-сервер, построенный только с помощью цикла событий.
<?phpuse ReactEventLoopLoop;требуется __DIR__ . '/vendor/autoload.php';$server =stream_socket_server('tcp://127.0.0.1:8080');stream_set_blocking($server, false); Loop::addReadStream($server, function ($server) {$conn =stream_socket_accept($server);$data = "HTTP/1.1 200 OKrnContent-Length: 3rnrnHin"; Loop::addWriteStream($conn, function ($conn) use (&$data) {$write = fwrite($conn, $data);if ($write === strlen($data)) {fclose($conn) ); Loop::removeWriteStream($conn); } Еще {$данные = substr($данные, $записано); } }); }); Loop::addPeriodicTimer(5, function () {$memory = Memory_get_usage() / 1024;$formatted = number_format($memory, 3).'K';echo "Текущее использование памяти: {$formatted}n"; });
См. также примеры.
Типичные приложения используют класс Loop
для использования цикла событий по умолчанию следующим образом:
используйте ReactEventLoopLoop; $timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; }); Loop::addTimer(1.0, function () use ($timer) { Loop::cancelTimer($timer);echo 'Done' . PHP_EOL; });
В качестве альтернативы вы также можете явно создать экземпляр цикла событий в начале, повторно использовать его во всей программе и, наконец, запустить его в конце программы следующим образом:
$loop = ReactEventLoopLoop::get();$timer = $loop->addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; });$loop->addTimer(1.0, function () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Done' . PHP_EOL; });$loop->run();
В то время как первый более краток, второй более ясен. В обоих случаях программа выполнит одни и те же действия.
Экземпляр цикла событий создается в начале программы. Это неявно делается при первом вызове класса Loop
(или при создании экземпляра любой реализации цикла вручную).
Цикл событий используется напрямую или передается как экземпляр в код библиотеки и приложения. В этом примере периодический таймер регистрируется в цикле событий, который просто выводит Tick
каждую долю секунды, пока другой таймер не остановит периодический таймер через секунду.
Цикл событий запускается в конце программы. Это делается автоматически при использовании класса Loop
или явно с помощью одного вызова run()
в конце программы.
Начиная с v1.2.0
, мы настоятельно рекомендуем использовать класс Loop
. Явные инструкции цикла все еще действительны и могут быть полезны в некоторых приложениях, особенно в период перехода к более краткому стилю.
Класс Loop
существует как удобный глобальный метод доступа к циклу событий.
Класс Loop
предоставляет все методы, существующие в LoopInterface
как статические методы:
бегать()
останавливаться()
добавитьТаймер()
добавитьпериодическийтаймер()
отменитьТаймер()
будущееТик()
добавитьСигнал()
удалитьСигнал()
добавитьReadStream()
добавитьWriteStream()
удалитьReadStream()
удалитьWriteStream()
Если вы работаете с циклом событий в коде приложения, зачастую проще всего напрямую взаимодействовать со статическими методами, определенными в классе Loop
, следующим образом:
используйте ReactEventLoopLoop; $timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; }); Loop::addTimer(1.0, function () use ($timer) { Loop::cancelTimer($timer);echo 'Done' . PHP_EOL; });
С другой стороны, если вы знакомы с объектно-ориентированным программированием (ООП) и внедрением зависимостей (DI), вы можете захотеть внедрить экземпляр цикла событий и вызвать методы экземпляра в LoopInterface
следующим образом:
использовать ReactEventLoopLoop; использовать ReactEventLoopLoopInterface; класс Greeter {частный $loop;публичная функция __construct(LoopInterface $loop) {$this->loop = $loop; } публичная функция приветствие (строка $name) {$this->loop->addTimer(1.0, function () use ($name) {echo 'Hello' . $name . '!' . PHP_EOL; }); } }$greeter = new Greeter(Loop::get());$greeter->greet('Алиса');$greeter->greet('Боб');
Каждый вызов статического метода будет перенаправлен как есть в базовый экземпляр цикла событий с помощью внутреннего вызова Loop::get()
. См. LoopInterface
для получения более подробной информации о доступных методах.
При использовании класса Loop
он автоматически выполняет цикл в конце программы. Это означает, что в следующем примере будет запланирован таймер и программа будет автоматически выполняться до тех пор, пока не сработает событие таймера:
используйте ReactEventLoopLoop; Loop::addTimer(1.0, function () {echo 'Hello' . PHP_EOL; });
Начиная с v1.2.0
, мы настоятельно рекомендуем использовать класс Loop
таким образом и опускать любые явные вызовы run()
. По причинам BC явный метод run()
по-прежнему действителен и может быть полезен в некоторых приложениях, особенно в период перехода к более краткому стилю.
Если вы не хотите, чтобы Loop
запускался автоматически, вы можете либо явно run()
, либо stop()
. Это может быть полезно, если вы используете такой глобальный обработчик исключений:
используйте ReactEventLoopLoop; Loop::addTimer(10.0, function () {echo 'Никогда не происходит'; });set_Exception_handler(function (Throwable $e) {echo 'Error:' . $e->getMessage() . PHP_EOL; Цикл::стоп(); }); создать новое исключение RuntimeException('Demo');
Метод get(): LoopInterface
можно использовать для получения текущего активного экземпляра цикла событий.
Этот метод всегда будет возвращать один и тот же экземпляр цикла событий на протяжении всего времени существования вашего приложения.
используйте ReactEventLoopLoop; используйте ReactEventLoopLoopInterface; $loop = Loop::get();assert($loop instanceof LoopInterface);assert($loop === Loop::get());
Это особенно полезно, если вы используете объектно-ориентированное программирование (ООП) и внедрение зависимостей (DI). В этом случае вы можете захотеть внедрить экземпляр цикла событий и вызвать методы экземпляра в LoopInterface
следующим образом:
использовать ReactEventLoopLoop; использовать ReactEventLoopLoopInterface; класс Greeter {частный $loop;публичная функция __construct(LoopInterface $loop) {$this->loop = $loop; } публичная функция приветствие (строка $name) {$this->loop->addTimer(1.0, function () use ($name) {echo 'Hello' . $name . '!' . PHP_EOL; }); } }$greeter = new Greeter(Loop::get());$greeter->greet('Алиса');$greeter->greet('Боб');
См. LoopInterface
для получения более подробной информации о доступных методах.
В дополнение к LoopInterface
существует ряд реализаций цикла событий.
Все циклы событий поддерживают следующие функции:
Опрос дескриптора файла
Одноразовые таймеры
Периодические таймеры
Отложенное выполнение на следующем тике цикла
Для большинства потребителей этого пакета базовая реализация цикла событий является деталью реализации. Вам следует использовать класс Loop
для автоматического создания нового экземпляра.
Передовой! Если вам явно нужна определенная реализация цикла событий, вы можете вручную создать экземпляр одного из следующих классов. Обратите внимание, что вам, возможно, придется сначала установить необходимые расширения PHP для соответствующей реализации цикла событий, иначе при создании будет выдано исключение BadMethodCallException
.
Цикл событий на stream_select()
.
Здесь используется stream_select()
и это единственная реализация, которая работает с PHP «из коробки».
Этот цикл событий работает «из коробки» в любой версии PHP. Это означает, что установка не требуется, и эта библиотека работает на всех платформах и поддерживаемых версиях PHP. Соответственно, класс Loop
будет использовать этот цикл событий по умолчанию, если вы не установите ни одно из расширений цикла событий, перечисленных ниже.
Под капотом он выполняет простой системный вызов select
. Этот системный вызов ограничен максимальным числом файловых дескрипторов FD_SETSIZE
(зависит от платформы, обычно 1024) и масштабируется с помощью O(m)
( m
— максимальное количество переданных файловых дескрипторов). Это означает, что вы можете столкнуться с проблемами при одновременной обработке тысяч потоков, и в этом случае вы можете рассмотреть возможность использования одной из альтернативных реализаций цикла событий, перечисленных ниже. Если ваш вариант использования входит в число многих распространенных вариантов использования, которые включают одновременную обработку только десятков или нескольких сотен потоков, то эта реализация цикла событий работает очень хорошо.
Если вы хотите использовать обработку сигналов (см. также addSignal()
ниже), для этой реализации цикла событий требуется ext-pcntl
. Это расширение доступно только для Unix-подобных платформ и не поддерживает Windows. Он обычно устанавливается как часть многих дистрибутивов PHP. Если это расширение отсутствует (или вы работаете в Windows), обработка сигналов не поддерживается и вместо этого выдается исключение BadMethodCallException
.
Известно, что этот цикл событий использует время настенных часов для планирования будущих таймеров при использовании любой версии PHP до 7.3, поскольку монотонный источник времени доступен только с PHP 7.3 ( hrtime()
). Хотя это не влияет на многие распространенные случаи использования, это важное различие для программ, которые полагаются на высокую точность времени или для систем, которые подвергаются прерывистой корректировке времени (скачкам времени). Это означает, что если вы запланируете срабатывание таймера через 30 секунд на PHP < 7.3, а затем скорректируете системное время вперед на 20 секунд, таймер может сработать через 10 секунд. См. также addTimer()
для получения более подробной информации.
Цикл событий на основе ext-event
.
При этом используется расширение event
PECL, которое предоставляет интерфейс для библиотеки libevent
. Сама libevent
поддерживает ряд специфичных для системы бэкэндов (epoll, kqueue).
Известно, что этот цикл работает с PHP 7.1–PHP 8+.
Цикл событий на основе ext-ev
.
В этом цикле используется расширение ev
PECL, которое обеспечивает интерфейс для библиотеки libev
. Сама libev
поддерживает ряд специфичных для системы бэкэндов (epoll, kqueue).
Известно, что этот цикл работает с PHP 7.1–PHP 8+.
Цикл событий на основе ext-uv
.
Этот цикл использует расширение uv
PECL, которое обеспечивает интерфейс для библиотеки libuv
. Сама libuv
поддерживает ряд специфичных для системы бэкэндов (epoll, kqueue).
Известно, что этот цикл работает с PHP 7.1–PHP 8+.
Метод run(): void
можно использовать для запуска цикла событий до тех пор, пока не останется задач для выполнения.
Для многих приложений этот метод является единственным видимым вызовом в цикле событий. Как правило, рекомендуется присоединить все к одному и тому же экземпляру цикла, а затем запустить цикл один раз в нижней части приложения.
$цикл->запустить();
Этот метод будет поддерживать цикл до тех пор, пока не останется задач для выполнения. Другими словами: этот метод будет блокироваться до тех пор, пока не будет удален последний таймер, поток и/или сигнал.
Аналогично, крайне важно убедиться, что приложение действительно вызывает этот метод один раз. Добавление прослушивателей в цикл и отсутствие его фактического запуска приведет к завершению работы приложения без фактического ожидания любого из подключенных прослушивателей.
Этот метод НЕ ДОЛЖЕН вызываться, пока цикл уже запущен. Этот метод МОЖЕТ быть вызван более одного раза после того, как он был явно вызван функцией stop()
или после его автоматической остановки, поскольку ранее ему больше нечего было делать.
Метод stop(): void
можно использовать для остановки работающего цикла событий.
Этот метод считается расширенным и его следует использовать с осторожностью. Как правило, рекомендуется разрешать циклу останавливаться только автоматически, когда ему больше нечего делать.
Этот метод можно использовать для явного указания циклу событий остановиться:
$loop->addTimer(3.0, function () use ($loop) {$loop->stop(); });
Вызов этого метода для экземпляра цикла, который в данный момент не выполняется, или для экземпляра цикла, который уже остановлен, не имеет никакого эффекта.
addTimer(float $interval, callable $callback): TimerInterface
можно использовать для постановки в очередь обратного вызова, который будет вызываться один раз по истечении заданного интервала.
Второй параметр ДОЛЖЕН быть функцией обратного вызова таймера, которая принимает экземпляр таймера в качестве единственного параметра. Если вы не используете экземпляр таймера внутри функции обратного вызова таймера, вы МОЖЕТЕ использовать функцию, которая вообще не имеет параметров.
Функция обратного вызова таймера НЕ ДОЛЖНА выдавать Exception
. Возвращаемое значение функции обратного вызова таймера будет игнорироваться и не будет иметь никакого эффекта, поэтому из соображений производительности рекомендуется не возвращать какие-либо чрезмерные структуры данных.
Этот метод возвращает экземпляр таймера. Тот же экземпляр таймера также будет передан в функцию обратного вызова таймера, как описано выше. Вы можете вызвать cancelTimer
чтобы отменить ожидающий таймер. В отличие от addPeriodicTimer()
, этот метод гарантирует, что обратный вызов будет вызван только один раз по истечении заданного интервала.
$loop->addTimer(0.8, function () {echo 'world!' . PHP_EOL; });$loop->addTimer(0.3, function () {echo 'привет'; });
См. также пример №1.
Если вы хотите получить доступ к каким-либо переменным внутри вашей функции обратного вызова, вы можете привязать произвольные данные к замыканию обратного вызова следующим образом:
функция hello($name, LoopInterface $loop) {$loop->addTimer(1.0, function () use ($name) {echo "привет $namen"; }); }hello('Тестер', $loop);
Этот интерфейс не требует какого-либо конкретного разрешения таймера, поэтому может потребоваться особая осторожность, если вы полагаетесь на очень высокую точность с точностью до миллисекунды или ниже. Реализации цикла событий ДОЛЖНЫ работать максимально эффективно и ДОЛЖНЫ обеспечивать точность не менее миллисекунды, если не указано иное. Известно, что многие существующие реализации цикла событий обеспечивают точность до микросекунд, но обычно не рекомендуется полагаться на такую высокую точность.
Аналогично, порядок выполнения таймеров, запланированных для одновременного выполнения (в пределах возможной точности), не гарантируется.
Этот интерфейс предполагает, что реализации цикла событий ДОЛЖНЫ использовать монотонный источник времени, если он доступен. Учитывая, что монотонный источник времени по умолчанию доступен только в PHP 7.3, реализации цикла событий МОГУТ вернуться к использованию времени настенных часов. Хотя это не влияет на многие распространенные случаи использования, это важное различие для программ, которые полагаются на высокую точность времени или для систем, которые подвержены прерывистой корректировке времени (скачкам времени). Это означает, что если вы запланируете срабатывание таймера через 30 секунд, а затем переместите системное время вперед на 20 секунд, таймер ДОЛЖЕН по-прежнему срабатывать через 30 секунд. Дополнительные сведения см. также в разделе «Реализации цикла событий».
Метод addPeriodicTimer(float $interval, callable $callback): TimerInterface
можно использовать для постановки в очередь обратного вызова, который будет вызываться повторно после заданного интервала.
Второй параметр ДОЛЖЕН быть функцией обратного вызова таймера, которая принимает экземпляр таймера в качестве единственного параметра. Если вы не используете экземпляр таймера внутри функции обратного вызова таймера, вы МОЖЕТЕ использовать функцию, которая вообще не имеет параметров.
Функция обратного вызова таймера НЕ ДОЛЖНА выдавать Exception
. Возвращаемое значение функции обратного вызова таймера будет игнорироваться и не будет иметь никакого эффекта, поэтому из соображений производительности рекомендуется не возвращать какие-либо чрезмерные структуры данных.
Этот метод возвращает экземпляр таймера. Тот же экземпляр таймера также будет передан в функцию обратного вызова таймера, как описано выше. В отличие от addTimer()
, этот метод гарантирует, что обратный вызов будет вызываться бесконечно после заданного интервала или до тех пор, пока вы не вызовете cancelTimer
.
$timer = $loop->addPeriodicTimer(0.1, function () {echo 'tick!' . PHP_EOL; });$loop->addTimer(1.0, function () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Done' . PHP_EOL; });
См. также пример №2.
Если вы хотите ограничить количество выполнений, вы можете привязать произвольные данные к закрытию обратного вызова следующим образом:
функция hello($name, LoopInterface $loop) {$n = 3;$loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {if ($n > 0) { --$n;echo "привет, $namen"; } Еще {$loop->cancelTimer($timer); } }); }hello('Тестер', $loop);
Этот интерфейс не требует какого-либо конкретного разрешения таймера, поэтому может потребоваться особая осторожность, если вы полагаетесь на очень высокую точность с точностью до миллисекунды или ниже. Реализации цикла событий ДОЛЖНЫ работать максимально эффективно и ДОЛЖНЫ обеспечивать точность не менее миллисекунды, если не указано иное. Известно, что многие существующие реализации цикла событий обеспечивают точность до микросекунд, но обычно не рекомендуется полагаться на такую высокую точность.
Аналогично, порядок выполнения таймеров, запланированных для одновременного выполнения (в пределах возможной точности), не гарантируется.
Этот интерфейс предполагает, что реализации цикла событий ДОЛЖНЫ использовать монотонный источник времени, если он доступен. Учитывая, что монотонный источник времени по умолчанию доступен только в PHP 7.3, реализации цикла событий МОГУТ вернуться к использованию времени настенных часов. Хотя это не влияет на многие распространенные случаи использования, это важное различие для программ, которые полагаются на высокую точность времени или для систем, которые подвержены прерывистой корректировке времени (скачкам времени). Это означает, что если вы запланируете срабатывание таймера через 30 секунд, а затем переместите системное время вперед на 20 секунд, таймер ДОЛЖЕН по-прежнему срабатывать через 30 секунд. Дополнительные сведения см. также в разделе «Реализации цикла событий».
Кроме того, периодические таймеры могут подвергаться смещению из-за перепланирования после каждого вызова. Таким образом, обычно не рекомендуется полагаться на это для интервалов высокой точности с точностью до миллисекунды или ниже.
Метод cancelTimer(TimerInterface $timer): void
можно использовать для отмены ожидающего таймера.
См. также addPeriodicTimer()
и пример №2.
Вызов этого метода для экземпляра таймера, который не был добавлен в этот экземпляр цикла, или для таймера, который уже был отменен, не имеет никакого эффекта.
Метод futureTick(callable $listener): void
можно использовать для планирования вызова обратного вызова в будущем тике цикла событий.
Это работает очень похоже на таймеры с интервалом в ноль секунд, но не требует затрат на планирование очереди таймеров.
Функция обратного вызова тика ДОЛЖНА иметь возможность принимать нулевые параметры.
Функция обратного вызова галочки НЕ ДОЛЖНА выдавать Exception
. Возвращаемое значение функции обратного вызова Tick будет игнорироваться и не будет иметь никакого эффекта, поэтому из соображений производительности рекомендуется не возвращать какие-либо чрезмерные структуры данных.
Если вы хотите получить доступ к каким-либо переменным внутри вашей функции обратного вызова, вы можете привязать произвольные данные к замыканию обратного вызова следующим образом:
функция hello($name, LoopInterface $loop) {$loop->futureTick(function () use ($name) {echo "привет $namen"; }); }hello('Тестер', $loop);
В отличие от таймеров, тиковые обратные вызовы гарантированно выполняются в том порядке, в котором они поставлены в очередь. Кроме того, если обратный вызов поставлен в очередь, отменить эту операцию невозможно.
Это часто используется для разбиения больших задач на более мелкие этапы (форма совместной многозадачности).
$loop->futureTick(function () {echo 'b'; });$loop->futureTick(function () {echo 'c'; });эхо 'а';
См. также пример №3.
Метод addSignal(int $signal, callable $listener): void
можно использовать для регистрации прослушивателя, который будет уведомляться, когда сигнал будет перехвачен этим процессом.
Это полезно для перехвата сигналов пользовательского прерывания или сигналов завершения работы от таких инструментов, как supervisor
или systemd
.
Второй параметр ДОЛЖЕН быть функцией обратного вызова прослушивателя, которая принимает сигнал в качестве единственного параметра. Если вы не используете сигнал внутри функции обратного вызова слушателя, вы МОЖЕТЕ использовать функцию, которая вообще не имеет параметров.
Функция обратного вызова прослушивателя НЕ ДОЛЖНА выдавать Exception
. Возвращаемое значение функции обратного вызова прослушивателя будет игнорироваться и не будет иметь никакого эффекта, поэтому из соображений производительности рекомендуется не возвращать какие-либо чрезмерные структуры данных.
$loop->addSignal(SIGINT, function (int $signal) {echo 'Пойман сигнал пользовательского прерывания' . PHP_EOL; });
См. также пример №4.
Сигнализация доступна только на Unix-подобных платформах, Windows не поддерживается из-за ограничений операционной системы. Этот метод может вызвать исключение BadMethodCallException
, если сигналы не поддерживаются на этой платформе, например, когда отсутствуют необходимые расширения.
Примечание. Прослушиватель можно добавить только один раз к одному и тому же сигналу, любые попытки добавить его более одного раза будут игнорироваться.
Метод removeSignal(int $signal, callable $listener): void
можно использовать для удаления ранее добавленного прослушивателя сигналов.
$loop->removeSignal(SIGINT, $listener);
Любые попытки удалить незарегистрированные прослушиватели будут игнорироваться.
Передовой! Обратите внимание, что этот низкоуровневый API считается расширенным использованием. В большинстве случаев использования вместо этого, вероятно, следует использовать читаемый Stream API более высокого уровня.
Метод addReadStream(resource $stream, callable $callback): void
можно использовать для регистрации прослушивателя, который будет получать уведомление, когда поток готов к чтению.
Первый параметр ДОЛЖЕН быть действительным ресурсом потока, который поддерживает проверку того, готов ли он к чтению с помощью этой реализации цикла. Один потоковой ресурс НЕ ДОЛЖЕН добавляться более одного раза. Вместо этого либо сначала вызовите removeReadStream()
, либо отреагируйте на это событие с помощью одного прослушивателя, а затем отправьте его из этого прослушивателя. Этот метод МОЖЕТ выдать Exception
, если данный тип ресурса не поддерживается этой реализацией цикла.
Второй параметр ДОЛЖЕН быть функцией обратного вызова прослушивателя, которая принимает ресурс потока в качестве единственного параметра. Если вы не используете ресурс потока внутри функции обратного вызова прослушивателя, вы МОЖЕТЕ использовать функцию, которая вообще не имеет параметров.
Функция обратного вызова прослушивателя НЕ ДОЛЖНА выдавать Exception
. Возвращаемое значение функции обратного вызова прослушивателя будет игнорироваться и не будет иметь никакого эффекта, поэтому из соображений производительности рекомендуется не возвращать какие-либо чрезмерные структуры данных.
Если вы хотите получить доступ к каким-либо переменным внутри вашей функции обратного вызова, вы можете привязать произвольные данные к замыканию обратного вызова следующим образом:
$loop->addReadStream($stream, function ($stream) use ($name) {echo $name . ' сказал: ' . fread($stream); });
См. также пример №11.
Вы можете вызвать removeReadStream()
, чтобы удалить прослушиватель событий чтения для этого потока.
Порядок выполнения прослушивателей при одновременной готовности нескольких потоков не гарантируется.
Известно, что некоторые реализации цикла событий запускают прослушиватель только в том случае, если поток становится доступным для чтения (запускается по краю), и могут не запускаться, если поток уже доступен для чтения с самого начала. Это также означает, что поток может быть не распознан как читаемый, если данные все еще остаются во внутренних буферах потока PHP. Таким образом, рекомендуется использоватьstream_set_read_buffer stream_set_read_buffer($stream, 0);
в этом случае отключить внутренний буфер чтения PHP.
Передовой! Обратите внимание, что этот низкоуровневый API считается расширенным использованием. В большинстве случаев вместо этого, вероятно, следует использовать записываемый Stream API более высокого уровня.
Метод addWriteStream(resource $stream, callable $callback): void
можно использовать для регистрации прослушивателя, который будет получать уведомление, когда поток готов к записи.
Первый параметр ДОЛЖЕН быть допустимым ресурсом потока, который поддерживает проверку готовности к записи с помощью этой реализации цикла. Один потоковой ресурс НЕ ДОЛЖЕН добавляться более одного раза. Вместо этого либо сначала вызовите removeWriteStream()
, либо отреагируйте на это событие с помощью одного прослушивателя, а затем отправьте его из этого прослушивателя. Этот метод МОЖЕТ выдать Exception
, если данный тип ресурса не поддерживается этой реализацией цикла.
Второй параметр ДОЛЖЕН быть функцией обратного вызова прослушивателя, которая принимает ресурс потока в качестве единственного параметра. Если вы не используете ресурс потока внутри функции обратного вызова прослушивателя, вы МОЖЕТЕ использовать функцию, которая вообще не имеет параметров.
Функция обратного вызова прослушивателя НЕ ДОЛЖНА выдавать Exception
. Возвращаемое значение функции обратного вызова прослушивателя будет игнорироваться и не будет иметь никакого эффекта, поэтому из соображений производительности рекомендуется не возвращать какие-либо чрезмерные структуры данных.
Если вы хотите получить доступ к каким-либо переменным внутри вашей функции обратного вызова, вы можете привязать произвольные данные к замыканию обратного вызова следующим образом:
$loop->addWriteStream($stream, function ($stream) use ($name) {fwrite($stream, 'Hello' . $name); });
См. также пример № 12.
Вы можете вызвать removeWriteStream()
, чтобы удалить прослушиватель событий записи для этого потока.
Порядок выполнения прослушивателей при одновременной готовности нескольких потоков не гарантируется.
Метод removeReadStream(resource $stream): void
можно использовать для удаления прослушивателя событий чтения для данного потока.
Удаление потока из цикла, который уже был удален, или попытка удалить поток, который никогда не добавлялся или является недействительным, не дает никакого эффекта.
Метод removeWriteStream(resource $stream): void
можно использовать для удаления прослушивателя событий записи для данного потока.
Удаление потока из цикла, который уже был удален, или попытка удалить поток, который никогда не добавлялся или является недействительным, не дает никакого эффекта.
Рекомендуемый способ установки этой библиотеки — через Composer. Впервые в Composer?
После выпуска этот проект будет следовать за SemVer. На данный момент будет установлена последняя разрабатываемая версия:
композитору требуется реакция/цикл событий:^3@dev
См. также CHANGELOG для получения подробной информации об обновлениях версий.
Этот проект предназначен для работы на любой платформе и, следовательно, не требует каких-либо расширений PHP и поддерживает работу с PHP 7.1 до текущей версии PHP 8+. Для этого проекта настоятельно рекомендуется использовать последнюю поддерживаемую версию PHP .
Установка любого расширения цикла событий предлагается, но совершенно необязательна. Дополнительные сведения см. также в разделе «Реализации цикла событий».
Чтобы запустить набор тестов, вам сначала необходимо клонировать этот репозиторий, а затем установить все зависимости через Composer:
установка композитора
Чтобы запустить набор тестов, перейдите в корень проекта и запустите:
поставщик/bin/phpunit
MIT, см. файл ЛИЦЕНЗИИ.
См. наш компонент Stream для получения дополнительной информации о том, как потоки используются в реальных приложениях.
См. нашу пользовательскую вики и зависимые ресурсы Packagist для получения списка пакетов, которые используют EventLoop в реальных приложениях.