Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
# EventLoop Component
2
 
3
[![Build Status](https://travis-ci.org/reactphp/event-loop.svg?branch=master)](https://travis-ci.org/reactphp/event-loop)
4
 
5
[ReactPHP](https://reactphp.org/)'s core reactor event loop that libraries can use for evented I/O.
6
 
7
In order for async based libraries to be interoperable, they need to use the
8
same event loop. This component provides a common `LoopInterface` that any
9
library can target. This allows them to be used in the same loop, with one
10
single [`run()`](#run) call that is controlled by the user.
11
 
12
**Table of Contents**
13
 
14
* [Quickstart example](#quickstart-example)
15
* [Usage](#usage)
16
  * [Factory](#factory)
17
    * [create()](#create)
18
  * [Loop implementations](#loop-implementations)
19
    * [StreamSelectLoop](#streamselectloop)
20
    * [ExtEventLoop](#exteventloop)
21
    * [ExtLibeventLoop](#extlibeventloop)
22
    * [ExtLibevLoop](#extlibevloop)
23
    * [ExtEvLoop](#extevloop)
24
    * [ExtUvLoop](#extuvloop)
25
  * [LoopInterface](#loopinterface)
26
    * [run()](#run)
27
    * [stop()](#stop)
28
    * [addTimer()](#addtimer)
29
    * [addPeriodicTimer()](#addperiodictimer)
30
    * [cancelTimer()](#canceltimer)
31
    * [futureTick()](#futuretick)
32
    * [addSignal()](#addsignal)
33
    * [removeSignal()](#removesignal)
34
    * [addReadStream()](#addreadstream)
35
    * [addWriteStream()](#addwritestream)
36
    * [removeReadStream()](#removereadstream)
37
    * [removeWriteStream()](#removewritestream)
38
* [Install](#install)
39
* [Tests](#tests)
40
* [License](#license)
41
* [More](#more)
42
 
43
## Quickstart example
44
 
45
Here is an async HTTP server built with just the event loop.
46
 
47
```php
48
$loop = React\EventLoop\Factory::create();
49
 
50
$server = stream_socket_server('tcp://127.0.0.1:8080');
51
stream_set_blocking($server, false);
52
 
53
$loop->addReadStream($server, function ($server) use ($loop) {
54
    $conn = stream_socket_accept($server);
55
    $data = "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nHi\n";
56
    $loop->addWriteStream($conn, function ($conn) use (&$data, $loop) {
57
        $written = fwrite($conn, $data);
58
        if ($written === strlen($data)) {
59
            fclose($conn);
60
            $loop->removeWriteStream($conn);
61
        } else {
62
            $data = substr($data, $written);
63
        }
64
    });
65
});
66
 
67
$loop->addPeriodicTimer(5, function () {
68
    $memory = memory_get_usage() / 1024;
69
    $formatted = number_format($memory, 3).'K';
70
    echo "Current memory usage: {$formatted}\n";
71
});
72
 
73
$loop->run();
74
```
75
 
76
See also the [examples](examples).
77
 
78
## Usage
79
 
80
Typical applications use a single event loop which is created at the beginning
81
and run at the end of the program.
82
 
83
```php
84
// [1]
85
$loop = React\EventLoop\Factory::create();
86
 
87
// [2]
88
$loop->addPeriodicTimer(1, function () {
89
    echo "Tick\n";
90
});
91
 
92
$stream = new React\Stream\ReadableResourceStream(
93
    fopen('file.txt', 'r'),
94
    $loop
95
);
96
 
97
// [3]
98
$loop->run();
99
```
100
 
101
1. The loop instance is created at the beginning of the program. A convenience
102
   factory [`React\EventLoop\Factory::create()`](#create) is provided by this library which
103
   picks the best available [loop implementation](#loop-implementations).
104
2. The loop instance is used directly or passed to library and application code.
105
   In this example, a periodic timer is registered with the event loop which
106
   simply outputs `Tick` every second and a
107
   [readable stream](https://github.com/reactphp/stream#readableresourcestream)
108
   is created by using ReactPHP's
109
   [stream component](https://github.com/reactphp/stream) for demonstration
110
   purposes.
111
3. The loop is run with a single [`$loop->run()`](#run) call at the end of the program.
112
 
113
### Factory
114
 
115
The `Factory` class exists as a convenient way to pick the best available
116
[event loop implementation](#loop-implementations).
117
 
118
#### create()
119
 
120
The `create(): LoopInterface` method can be used to create a new event loop
121
instance:
122
 
123
```php
124
$loop = React\EventLoop\Factory::create();
125
```
126
 
127
This method always returns an instance implementing [`LoopInterface`](#loopinterface),
128
the actual [event loop implementation](#loop-implementations) is an implementation detail.
129
 
130
This method should usually only be called once at the beginning of the program.
131
 
132
### Loop implementations
133
 
134
In addition to the [`LoopInterface`](#loopinterface), there are a number of
135
event loop implementations provided.
136
 
137
All of the event loops support these features:
138
 
139
* File descriptor polling
140
* One-off timers
141
* Periodic timers
142
* Deferred execution on future loop tick
143
 
144
For most consumers of this package, the underlying event loop implementation is
145
an implementation detail.
146
You should use the [`Factory`](#factory) to automatically create a new instance.
147
 
148
Advanced! If you explicitly need a certain event loop implementation, you can
149
manually instantiate one of the following classes.
150
Note that you may have to install the required PHP extensions for the respective
151
event loop implementation first or they will throw a `BadMethodCallException` on creation.
152
 
153
#### StreamSelectLoop
154
 
155
A `stream_select()` based event loop.
156
 
157
This uses the [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php)
158
function and is the only implementation which works out of the box with PHP.
159
 
160
This event loop works out of the box on PHP 5.3 through PHP 7+ and HHVM.
161
This means that no installation is required and this library works on all
162
platforms and supported PHP versions.
163
Accordingly, the [`Factory`](#factory) will use this event loop by default if
164
you do not install any of the event loop extensions listed below.
165
 
166
Under the hood, it does a simple `select` system call.
167
This system call is limited to the maximum file descriptor number of
168
`FD_SETSIZE` (platform dependent, commonly 1024) and scales with `O(m)`
169
(`m` being the maximum file descriptor number passed).
170
This means that you may run into issues when handling thousands of streams
171
concurrently and you may want to look into using one of the alternative
172
event loop implementations listed below in this case.
173
If your use case is among the many common use cases that involve handling only
174
dozens or a few hundred streams at once, then this event loop implementation
175
performs really well.
176
 
177
If you want to use signal handling (see also [`addSignal()`](#addsignal) below),
178
this event loop implementation requires `ext-pcntl`.
179
This extension is only available for Unix-like platforms and does not support
180
Windows.
181
It is commonly installed as part of many PHP distributions.
182
If this extension is missing (or you're running on Windows), signal handling is
183
not supported and throws a `BadMethodCallException` instead.
184
 
185
This event loop is known to rely on wall-clock time to schedule future timers
186
when using any version before PHP 7.3, because a monotonic time source is
187
only available as of PHP 7.3 (`hrtime()`).
188
While this does not affect many common use cases, this is an important
189
distinction for programs that rely on a high time precision or on systems
190
that are subject to discontinuous time adjustments (time jumps).
191
This means that if you schedule a timer to trigger in 30s on PHP < 7.3 and
192
then adjust your system time forward by 20s, the timer may trigger in 10s.
193
See also [`addTimer()`](#addtimer) for more details.
194
 
195
#### ExtEventLoop
196
 
197
An `ext-event` based event loop.
198
 
199
This uses the [`event` PECL extension](https://pecl.php.net/package/event).
200
It supports the same backends as libevent.
201
 
202
This loop is known to work with PHP 5.4 through PHP 7+.
203
 
204
#### ExtEvLoop
205
 
206
An `ext-ev` based event loop.
207
 
208
This loop uses the [`ev` PECL extension](https://pecl.php.net/package/ev), that
209
provides an interface to `libev` library.
210
 
211
This loop is known to work with PHP 5.4 through PHP 7+.
212
 
213
#### ExtUvLoop
214
 
215
An `ext-uv` based event loop.
216
 
217
This loop uses the [`uv` PECL extension](https://pecl.php.net/package/uv), that
218
provides an interface to `libuv` library.
219
 
220
This loop is known to work with PHP 7+.
221
 
222
#### ExtLibeventLoop
223
 
224
An `ext-libevent` based event loop.
225
 
226
This uses the [`libevent` PECL extension](https://pecl.php.net/package/libevent).
227
`libevent` itself supports a number of system-specific backends (epoll, kqueue).
228
 
229
This event loop does only work with PHP 5.
230
An [unofficial update](https://github.com/php/pecl-event-libevent/pull/2) for
231
PHP 7 does exist, but it is known to cause regular crashes due to `SEGFAULT`s.
232
To reiterate: Using this event loop on PHP 7 is not recommended.
233
Accordingly, the [`Factory`](#factory) will not try to use this event loop on
234
PHP 7.
235
 
236
This event loop is known to trigger a readable listener only if
237
the stream *becomes* readable (edge-triggered) and may not trigger if the
238
stream has already been readable from the beginning.
239
This also implies that a stream may not be recognized as readable when data
240
is still left in PHP's internal stream buffers.
241
As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
242
to disable PHP's internal read buffer in this case.
243
See also [`addReadStream()`](#addreadstream) for more details.
244
 
245
#### ExtLibevLoop
246
 
247
An `ext-libev` based event loop.
248
 
249
This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev).
250
It supports the same backends as libevent.
251
 
252
This loop does only work with PHP 5.
253
An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8)
254
to happen any time soon.
255
 
256
### LoopInterface
257
 
258
#### run()
259
 
260
The `run(): void` method can be used to
261
run the event loop until there are no more tasks to perform.
262
 
263
For many applications, this method is the only directly visible
264
invocation on the event loop.
265
As a rule of thumb, it is usally recommended to attach everything to the
266
same loop instance and then run the loop once at the bottom end of the
267
application.
268
 
269
```php
270
$loop->run();
271
```
272
 
273
This method will keep the loop running until there are no more tasks
274
to perform. In other words: This method will block until the last
275
timer, stream and/or signal has been removed.
276
 
277
Likewise, it is imperative to ensure the application actually invokes
278
this method once. Adding listeners to the loop and missing to actually
279
run it will result in the application exiting without actually waiting
280
for any of the attached listeners.
281
 
282
This method MUST NOT be called while the loop is already running.
283
This method MAY be called more than once after it has explicity been
284
[`stop()`ped](#stop) or after it automatically stopped because it
285
previously did no longer have anything to do.
286
 
287
#### stop()
288
 
289
The `stop(): void` method can be used to
290
instruct a running event loop to stop.
291
 
292
This method is considered advanced usage and should be used with care.
293
As a rule of thumb, it is usually recommended to let the loop stop
294
only automatically when it no longer has anything to do.
295
 
296
This method can be used to explicitly instruct the event loop to stop:
297
 
298
```php
299
$loop->addTimer(3.0, function () use ($loop) {
300
    $loop->stop();
301
});
302
```
303
 
304
Calling this method on a loop instance that is not currently running or
305
on a loop instance that has already been stopped has no effect.
306
 
307
#### addTimer()
308
 
309
The `addTimer(float $interval, callable $callback): TimerInterface` method can be used to
310
enqueue a callback to be invoked once after the given interval.
311
 
312
The timer callback function MUST be able to accept a single parameter,
313
the timer instance as also returned by this method or you MAY use a
314
function which has no parameters at all.
315
 
316
The timer callback function MUST NOT throw an `Exception`.
317
The return value of the timer callback function will be ignored and has
318
no effect, so for performance reasons you're recommended to not return
319
any excessive data structures.
320
 
321
Unlike [`addPeriodicTimer()`](#addperiodictimer), this method will ensure
322
the callback will be invoked only once after the given interval.
323
You can invoke [`cancelTimer`](#canceltimer) to cancel a pending timer.
324
 
325
```php
326
$loop->addTimer(0.8, function () {
327
    echo 'world!' . PHP_EOL;
328
});
329
 
330
$loop->addTimer(0.3, function () {
331
    echo 'hello ';
332
});
333
```
334
 
335
See also [example #1](examples).
336
 
337
If you want to access any variables within your callback function, you
338
can bind arbitrary data to a callback closure like this:
339
 
340
```php
341
function hello($name, LoopInterface $loop)
342
{
343
    $loop->addTimer(1.0, function () use ($name) {
344
        echo "hello $name\n";
345
    });
346
}
347
 
348
hello('Tester', $loop);
349
```
350
 
351
This interface does not enforce any particular timer resolution, so
352
special care may have to be taken if you rely on very high precision with
353
millisecond accuracy or below. Event loop implementations SHOULD work on
354
a best effort basis and SHOULD provide at least millisecond accuracy
355
unless otherwise noted. Many existing event loop implementations are
356
known to provide microsecond accuracy, but it's generally not recommended
357
to rely on this high precision.
358
 
359
Similarly, the execution order of timers scheduled to execute at the
360
same time (within its possible accuracy) is not guaranteed.
361
 
362
This interface suggests that event loop implementations SHOULD use a
363
monotonic time source if available. Given that a monotonic time source is
364
only available as of PHP 7.3 by default, event loop implementations MAY
365
fall back to using wall-clock time.
366
While this does not affect many common use cases, this is an important
367
distinction for programs that rely on a high time precision or on systems
368
that are subject to discontinuous time adjustments (time jumps).
369
This means that if you schedule a timer to trigger in 30s and then adjust
370
your system time forward by 20s, the timer SHOULD still trigger in 30s.
371
See also [event loop implementations](#loop-implementations) for more details.
372
 
373
#### addPeriodicTimer()
374
 
375
The `addPeriodicTimer(float $interval, callable $callback): TimerInterface` method can be used to
376
enqueue a callback to be invoked repeatedly after the given interval.
377
 
378
The timer callback function MUST be able to accept a single parameter,
379
the timer instance as also returned by this method or you MAY use a
380
function which has no parameters at all.
381
 
382
The timer callback function MUST NOT throw an `Exception`.
383
The return value of the timer callback function will be ignored and has
384
no effect, so for performance reasons you're recommended to not return
385
any excessive data structures.
386
 
387
Unlike [`addTimer()`](#addtimer), this method will ensure the the
388
callback will be invoked infinitely after the given interval or until you
389
invoke [`cancelTimer`](#canceltimer).
390
 
391
```php
392
$timer = $loop->addPeriodicTimer(0.1, function () {
393
    echo 'tick!' . PHP_EOL;
394
});
395
 
396
$loop->addTimer(1.0, function () use ($loop, $timer) {
397
    $loop->cancelTimer($timer);
398
    echo 'Done' . PHP_EOL;
399
});
400
```
401
 
402
See also [example #2](examples).
403
 
404
If you want to limit the number of executions, you can bind
405
arbitrary data to a callback closure like this:
406
 
407
```php
408
function hello($name, LoopInterface $loop)
409
{
410
    $n = 3;
411
    $loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {
412
        if ($n > 0) {
413
            --$n;
414
            echo "hello $name\n";
415
        } else {
416
            $loop->cancelTimer($timer);
417
        }
418
    });
419
}
420
 
421
hello('Tester', $loop);
422
```
423
 
424
This interface does not enforce any particular timer resolution, so
425
special care may have to be taken if you rely on very high precision with
426
millisecond accuracy or below. Event loop implementations SHOULD work on
427
a best effort basis and SHOULD provide at least millisecond accuracy
428
unless otherwise noted. Many existing event loop implementations are
429
known to provide microsecond accuracy, but it's generally not recommended
430
to rely on this high precision.
431
 
432
Similarly, the execution order of timers scheduled to execute at the
433
same time (within its possible accuracy) is not guaranteed.
434
 
435
This interface suggests that event loop implementations SHOULD use a
436
monotonic time source if available. Given that a monotonic time source is
437
only available as of PHP 7.3 by default, event loop implementations MAY
438
fall back to using wall-clock time.
439
While this does not affect many common use cases, this is an important
440
distinction for programs that rely on a high time precision or on systems
441
that are subject to discontinuous time adjustments (time jumps).
442
This means that if you schedule a timer to trigger in 30s and then adjust
443
your system time forward by 20s, the timer SHOULD still trigger in 30s.
444
See also [event loop implementations](#loop-implementations) for more details.
445
 
446
Additionally, periodic timers may be subject to timer drift due to
447
re-scheduling after each invocation. As such, it's generally not
448
recommended to rely on this for high precision intervals with millisecond
449
accuracy or below.
450
 
451
#### cancelTimer()
452
 
453
The `cancelTimer(TimerInterface $timer): void` method can be used to
454
cancel a pending timer.
455
 
456
See also [`addPeriodicTimer()`](#addperiodictimer) and [example #2](examples).
457
 
458
Calling this method on a timer instance that has not been added to this
459
loop instance or on a timer that has already been cancelled has no effect.
460
 
461
#### futureTick()
462
 
463
The `futureTick(callable $listener): void` method can be used to
464
schedule a callback to be invoked on a future tick of the event loop.
465
 
466
This works very much similar to timers with an interval of zero seconds,
467
but does not require the overhead of scheduling a timer queue.
468
 
469
The tick callback function MUST be able to accept zero parameters.
470
 
471
The tick callback function MUST NOT throw an `Exception`.
472
The return value of the tick callback function will be ignored and has
473
no effect, so for performance reasons you're recommended to not return
474
any excessive data structures.
475
 
476
If you want to access any variables within your callback function, you
477
can bind arbitrary data to a callback closure like this:
478
 
479
```php
480
function hello($name, LoopInterface $loop)
481
{
482
    $loop->futureTick(function () use ($name) {
483
        echo "hello $name\n";
484
    });
485
}
486
 
487
hello('Tester', $loop);
488
```
489
 
490
Unlike timers, tick callbacks are guaranteed to be executed in the order
491
they are enqueued.
492
Also, once a callback is enqueued, there's no way to cancel this operation.
493
 
494
This is often used to break down bigger tasks into smaller steps (a form
495
of cooperative multitasking).
496
 
497
```php
498
$loop->futureTick(function () {
499
    echo 'b';
500
});
501
$loop->futureTick(function () {
502
    echo 'c';
503
});
504
echo 'a';
505
```
506
 
507
See also [example #3](examples).
508
 
509
#### addSignal()
510
 
511
The `addSignal(int $signal, callable $listener): void` method can be used to
512
register a listener to be notified when a signal has been caught by this process.
513
 
514
This is useful to catch user interrupt signals or shutdown signals from
515
tools like `supervisor` or `systemd`.
516
 
517
The listener callback function MUST be able to accept a single parameter,
518
the signal added by this method or you MAY use a function which
519
has no parameters at all.
520
 
521
The listener callback function MUST NOT throw an `Exception`.
522
The return value of the listener callback function will be ignored and has
523
no effect, so for performance reasons you're recommended to not return
524
any excessive data structures.
525
 
526
```php
527
$loop->addSignal(SIGINT, function (int $signal) {
528
    echo 'Caught user interrupt signal' . PHP_EOL;
529
});
530
```
531
 
532
See also [example #4](examples).
533
 
534
Signaling is only available on Unix-like platform, Windows isn't
535
supported due to operating system limitations.
536
This method may throw a `BadMethodCallException` if signals aren't
537
supported on this platform, for example when required extensions are
538
missing.
539
 
540
**Note: A listener can only be added once to the same signal, any
541
attempts to add it more then once will be ignored.**
542
 
543
#### removeSignal()
544
 
545
The `removeSignal(int $signal, callable $listener): void` method can be used to
546
remove a previously added signal listener.
547
 
548
```php
549
$loop->removeSignal(SIGINT, $listener);
550
```
551
 
552
Any attempts to remove listeners that aren't registered will be ignored.
553
 
554
#### addReadStream()
555
 
556
> Advanced! Note that this low-level API is considered advanced usage.
557
  Most use cases should probably use the higher-level
558
  [readable Stream API](https://github.com/reactphp/stream#readablestreaminterface)
559
  instead.
560
 
561
The `addReadStream(resource $stream, callable $callback): void` method can be used to
562
register a listener to be notified when a stream is ready to read.
563
 
564
The first parameter MUST be a valid stream resource that supports
565
checking whether it is ready to read by this loop implementation.
566
A single stream resource MUST NOT be added more than once.
567
Instead, either call [`removeReadStream()`](#removereadstream) first or
568
react to this event with a single listener and then dispatch from this
569
listener. This method MAY throw an `Exception` if the given resource type
570
is not supported by this loop implementation.
571
 
572
The listener callback function MUST be able to accept a single parameter,
573
the stream resource added by this method or you MAY use a function which
574
has no parameters at all.
575
 
576
The listener callback function MUST NOT throw an `Exception`.
577
The return value of the listener callback function will be ignored and has
578
no effect, so for performance reasons you're recommended to not return
579
any excessive data structures.
580
 
581
If you want to access any variables within your callback function, you
582
can bind arbitrary data to a callback closure like this:
583
 
584
```php
585
$loop->addReadStream($stream, function ($stream) use ($name) {
586
    echo $name . ' said: ' . fread($stream);
587
});
588
```
589
 
590
See also [example #11](examples).
591
 
592
You can invoke [`removeReadStream()`](#removereadstream) to remove the
593
read event listener for this stream.
594
 
595
The execution order of listeners when multiple streams become ready at
596
the same time is not guaranteed.
597
 
598
Some event loop implementations are known to only trigger the listener if
599
the stream *becomes* readable (edge-triggered) and may not trigger if the
600
stream has already been readable from the beginning.
601
This also implies that a stream may not be recognized as readable when data
602
is still left in PHP's internal stream buffers.
603
As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
604
to disable PHP's internal read buffer in this case.
605
 
606
#### addWriteStream()
607
 
608
> Advanced! Note that this low-level API is considered advanced usage.
609
  Most use cases should probably use the higher-level
610
  [writable Stream API](https://github.com/reactphp/stream#writablestreaminterface)
611
  instead.
612
 
613
The `addWriteStream(resource $stream, callable $callback): void` method can be used to
614
register a listener to be notified when a stream is ready to write.
615
 
616
The first parameter MUST be a valid stream resource that supports
617
checking whether it is ready to write by this loop implementation.
618
A single stream resource MUST NOT be added more than once.
619
Instead, either call [`removeWriteStream()`](#removewritestream) first or
620
react to this event with a single listener and then dispatch from this
621
listener. This method MAY throw an `Exception` if the given resource type
622
is not supported by this loop implementation.
623
 
624
The listener callback function MUST be able to accept a single parameter,
625
the stream resource added by this method or you MAY use a function which
626
has no parameters at all.
627
 
628
The listener callback function MUST NOT throw an `Exception`.
629
The return value of the listener callback function will be ignored and has
630
no effect, so for performance reasons you're recommended to not return
631
any excessive data structures.
632
 
633
If you want to access any variables within your callback function, you
634
can bind arbitrary data to a callback closure like this:
635
 
636
```php
637
$loop->addWriteStream($stream, function ($stream) use ($name) {
638
    fwrite($stream, 'Hello ' . $name);
639
});
640
```
641
 
642
See also [example #12](examples).
643
 
644
You can invoke [`removeWriteStream()`](#removewritestream) to remove the
645
write event listener for this stream.
646
 
647
The execution order of listeners when multiple streams become ready at
648
the same time is not guaranteed.
649
 
650
#### removeReadStream()
651
 
652
The `removeReadStream(resource $stream): void` method can be used to
653
remove the read event listener for the given stream.
654
 
655
Removing a stream from the loop that has already been removed or trying
656
to remove a stream that was never added or is invalid has no effect.
657
 
658
#### removeWriteStream()
659
 
660
The `removeWriteStream(resource $stream): void` method can be used to
661
remove the write event listener for the given stream.
662
 
663
Removing a stream from the loop that has already been removed or trying
664
to remove a stream that was never added or is invalid has no effect.
665
 
666
## Install
667
 
668
The recommended way to install this library is [through Composer](https://getcomposer.org).
669
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
670
 
671
This project follows [SemVer](https://semver.org/).
672
This will install the latest supported version:
673
 
674
```bash
675
$ composer require react/event-loop:^1.1.1
676
```
677
 
678
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
679
 
680
This project aims to run on any platform and thus does not require any PHP
681
extensions and supports running on legacy PHP 5.3 through current PHP 7+ and
682
HHVM.
683
It's *highly recommended to use PHP 7+* for this project.
684
 
685
Installing any of the event loop extensions is suggested, but entirely optional.
686
See also [event loop implementations](#loop-implementations) for more details.
687
 
688
## Tests
689
 
690
To run the test suite, you first need to clone this repo and then install all
691
dependencies [through Composer](https://getcomposer.org):
692
 
693
```bash
694
$ composer install
695
```
696
 
697
To run the test suite, go to the project root and run:
698
 
699
```bash
700
$ php vendor/bin/phpunit
701
```
702
 
703
## License
704
 
705
MIT, see [LICENSE file](LICENSE).
706
 
707
## More
708
 
709
* See our [Stream component](https://github.com/reactphp/stream) for more
710
  information on how streams are used in real-world applications.
711
* See our [users wiki](https://github.com/reactphp/react/wiki/Users) and the
712
  [dependents on Packagist](https://packagist.org/packages/react/event-loop/dependents)
713
  for a list of packages that use the EventLoop in real-world applications.