Skip to content

Commit 0307e73

Browse files
committed
Add static Loop methods
1 parent 01a2900 commit 0307e73

17 files changed

+497
-65
lines changed

README.md

+146-15
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ single [`run()`](#run) call that is controlled by the user.
1414
* [Quickstart example](#quickstart-example)
1515
* [Usage](#usage)
1616
* [Loop](#loop)
17+
* [Loop methods](#loop-methods)
1718
* [get()](#get)
1819
* [Factory](#factory)
1920
* [~~create()~~](#create)
@@ -52,35 +53,53 @@ use React\EventLoop\Loop;
5253
$server = stream_socket_server('tcp://127.0.0.1:8080');
5354
stream_set_blocking($server, false);
5455

55-
Loop::get()->addReadStream($server, function ($server) {
56+
Loop::addReadStream($server, function ($server) {
5657
$conn = stream_socket_accept($server);
5758
$data = "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nHi\n";
58-
Loop::get()->addWriteStream($conn, function ($conn) use (&$data) {
59+
Loop::addWriteStream($conn, function ($conn) use (&$data) {
5960
$written = fwrite($conn, $data);
6061
if ($written === strlen($data)) {
6162
fclose($conn);
62-
Loop::get()->removeWriteStream($conn);
63+
Loop::removeWriteStream($conn);
6364
} else {
6465
$data = substr($data, $written);
6566
}
6667
});
6768
});
6869

69-
Loop::get()->addPeriodicTimer(5, function () {
70+
Loop::addPeriodicTimer(5, function () {
7071
$memory = memory_get_usage() / 1024;
7172
$formatted = number_format($memory, 3).'K';
7273
echo "Current memory usage: {$formatted}\n";
7374
});
7475

75-
Loop::get()->run();
76+
Loop::run();
7677
```
7778

7879
See also the [examples](examples).
7980

8081
## Usage
8182

82-
Typical applications use a single event loop which is created at the beginning
83-
and run at the end of the program.
83+
As of `v1.2.0`, typical applications would use the [`Loop` object](#loop)
84+
to use the currently active event loop instance like this:
85+
86+
```php
87+
use React\EventLoop\Loop;
88+
89+
$timer = Loop::addPeriodicTimer(0.1, function () {
90+
echo "Tick" . PHP_EOL;
91+
});
92+
Loop::addTimer(1.0, function () use ($timer) {
93+
Loop::cancelTimer($timer);
94+
echo 'Done' . PHP_EOL;
95+
});
96+
97+
Loop::run();
98+
```
99+
100+
As an alternative, you can also explicitly create an event loop instance at the
101+
beginning, reuse it throughout your program and finally run it at the end of the
102+
program like this:
84103

85104
```php
86105
$loop = React\EventLoop\Loop::get(); // or deprecated React\EventLoop\Factory::create();
@@ -96,6 +115,9 @@ $loop->addTimer(1.0, function () use ($loop, $timer) {
96115
$loop->run();
97116
```
98117

118+
While the former is more concise, the latter is more explicit.
119+
In both cases, the program would perform the exact same steps.
120+
99121
1. The event loop instance is created at the beginning of the program. This is
100122
implicitly done the first time you call the [`Loop` class](#loop) or
101123
explicitly when using the deprecated [`Factory::create() method`](#create)
@@ -107,28 +129,137 @@ $loop->run();
107129
3. The event loop is run at the end of the program with a single [`run()`](#run)
108130
call at the end of the program.
109131

132+
As of `v1.2.0`, we highly recommend using the [`Loop` class](#loop).
133+
The explicit loop instructions are still valid and may still be useful in some
134+
applications, especially for a transition period towards the more concise style.
135+
110136
### Loop
111137

112138
The `Loop` class exists as a convenient global accessor for the event loop.
113139

114-
#### get()
140+
#### Loop methods
141+
142+
The `Loop` class provides all methods that exist on the [`LoopInterface`](#loopinterface)
143+
as static methods:
115144

116-
The `get(): LoopInterface` method is the preferred way to get and use the event loop. With
117-
it there is no need to always pass the loop around anymore.
145+
* [run()](#run)
146+
* [stop()](#stop)
147+
* [addTimer()](#addtimer)
148+
* [addPeriodicTimer()](#addperiodictimer)
149+
* [cancelTimer()](#canceltimer)
150+
* [futureTick()](#futuretick)
151+
* [addSignal()](#addsignal)
152+
* [removeSignal()](#removesignal)
153+
* [addReadStream()](#addreadstream)
154+
* [addWriteStream()](#addwritestream)
155+
* [removeReadStream()](#removereadstream)
156+
* [removeWriteStream()](#removewritestream)
157+
158+
If you're working with the event loop in your application code, it's often
159+
easiest to directly interface with the static methods defined on the `Loop` class
160+
like this:
118161

119162
```php
120163
use React\EventLoop\Loop;
121164

122-
Loop::get()->addTimer(0.02, function () {
123-
echo 'World!';
165+
$timer = Loop::addPeriodicTimer(0.1, function () {
166+
echo 'tick!' . PHP_EOL;
124167
});
125-
Loop::get()->addTimer(0.01, function () {
126-
echo 'Hello ';
168+
169+
Loop::addTimer(1.0, function () use ($timer) {
170+
Loop::cancelTimer($timer);
171+
echo 'Done' . PHP_EOL;
127172
});
128173

129-
Loop::get()->run();
174+
Loop::run();
130175
```
131176

177+
On the other hand, if you're familiar with object-oriented programming (OOP) and
178+
dependency injection (DI), you may want to inject an event loop instance and
179+
invoke instance methods on the `LoopInterface` like this:
180+
181+
```php
182+
use React\EventLoop\Loop;
183+
use React\EventLoop\LoopInterface;
184+
185+
class Greeter
186+
{
187+
private $loop;
188+
189+
public function __construct(LoopInterface $loop)
190+
{
191+
$this->loop = $loop;
192+
}
193+
194+
public function greet(string $name)
195+
{
196+
$this->loop->addTimer(1.0, function () use ($name) {
197+
echo 'Hello ' . $name . '!' . PHP_EOL;
198+
});
199+
}
200+
}
201+
202+
$greeter = new Greeter(Loop::get());
203+
$greeter->greet('Alice');
204+
$greeter->greet('Bob');
205+
206+
Loop::run();
207+
```
208+
209+
See [`LoopInterface`](#loopinterface) for more details about available methods.
210+
211+
#### get()
212+
213+
The `get(): LoopInterface` method can be used to
214+
get the currently active event loop instance.
215+
216+
This method will always return the same event loop instance throughout the
217+
lifetime of your application.
218+
219+
```php
220+
use React\EventLoop\Loop;
221+
use React\EventLoop\LoopInterface;
222+
223+
$loop = Loop::get();
224+
225+
assert($loop instanceof LoopInterface);
226+
assert($loop === Loop::get());
227+
```
228+
229+
This is particularly useful if you're using object-oriented programming (OOP)
230+
and dependency injection (DI). In this case, you may want to inject an event
231+
loop instance and invoke instance methods on the `LoopInterface` like this:
232+
233+
```php
234+
use React\EventLoop\Loop;
235+
use React\EventLoop\LoopInterface;
236+
237+
class Greeter
238+
{
239+
private $loop;
240+
241+
public function __construct(LoopInterface $loop)
242+
{
243+
$this->loop = $loop;
244+
}
245+
246+
public function greet(string $name)
247+
{
248+
$this->loop->addTimer(1.0, function () use ($name) {
249+
echo 'Hello ' . $name . '!' . PHP_EOL;
250+
});
251+
}
252+
}
253+
254+
$greeter = new Greeter(Loop::get());
255+
$greeter->greet('Alice');
256+
$greeter->greet('Bob');
257+
258+
Loop::run();
259+
```
260+
261+
See [`LoopInterface`](#loopinterface) for more details about available methods.
262+
132263
### Factory
133264

134265
The `Factory` class exists as a convenient way to pick the best available

examples/01-timers.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
require __DIR__ . '/../vendor/autoload.php';
66

7-
Loop::get()->addTimer(0.8, function () {
7+
Loop::addTimer(0.8, function () {
88
echo 'world!' . PHP_EOL;
99
});
1010

11-
Loop::get()->addTimer(0.3, function () {
11+
Loop::addTimer(0.3, function () {
1212
echo 'hello ';
1313
});
1414

15-
Loop::get()->run();
15+
Loop::run();

examples/02-periodic.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
require __DIR__ . '/../vendor/autoload.php';
66

7-
$timer = Loop::get()->addPeriodicTimer(0.1, function () {
7+
$timer = Loop::addPeriodicTimer(0.1, function () {
88
echo 'tick!' . PHP_EOL;
99
});
1010

11-
Loop::get()->addTimer(1.0, function () use ($timer) {
12-
Loop::get()->cancelTimer($timer);
11+
Loop::addTimer(1.0, function () use ($timer) {
12+
Loop::cancelTimer($timer);
1313
echo 'Done' . PHP_EOL;
1414
});
1515

16-
Loop::get()->run();
16+
Loop::run();

examples/03-ticks.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
require __DIR__ . '/../vendor/autoload.php';
66

7-
Loop::get()->futureTick(function () {
7+
Loop::futureTick(function () {
88
echo 'b';
99
});
10-
Loop::get()->futureTick(function () {
10+
Loop::futureTick(function () {
1111
echo 'c';
1212
});
1313
echo 'a';
1414

15-
Loop::get()->run();
15+
Loop::run();

examples/04-signals.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
exit(1);
1010
}
1111

12-
Loop::get()->addSignal(SIGINT, $func = function ($signal) use (&$func) {
12+
Loop::addSignal(SIGINT, $func = function ($signal) use (&$func) {
1313
echo 'Signal: ', (string)$signal, PHP_EOL;
14-
Loop::get()->removeSignal(SIGINT, $func);
14+
Loop::removeSignal(SIGINT, $func);
1515
});
1616

1717
echo 'Listening for SIGINT. Use "kill -SIGINT ' . getmypid() . '" or CTRL+C' . PHP_EOL;
1818

19-
Loop::get()->run();
19+
Loop::run();

examples/11-consume-stdin.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111

1212
// read everything from STDIN and report number of bytes
1313
// for illustration purposes only, should use react/stream instead
14-
Loop::get()->addReadStream(STDIN, function ($stream) {
14+
Loop::addReadStream(STDIN, function ($stream) {
1515
$chunk = fread($stream, 64 * 1024);
1616

1717
// reading nothing means we reached EOF
1818
if ($chunk === '') {
19-
Loop::get()->removeReadStream($stream);
19+
Loop::removeReadStream($stream);
2020
stream_set_blocking($stream, true);
2121
fclose($stream);
2222
return;
@@ -25,4 +25,4 @@
2525
echo strlen($chunk) . ' bytes' . PHP_EOL;
2626
});
2727

28-
Loop::get()->run();
28+
Loop::run();

examples/12-generate-yes.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717

1818
// write data to STDOUT whenever its write buffer accepts data
1919
// for illustrations purpose only, should use react/stream instead
20-
Loop::get()->addWriteStream(STDOUT, function ($stdout) use (&$data) {
20+
Loop::addWriteStream(STDOUT, function ($stdout) use (&$data) {
2121
// try to write data
2222
$r = fwrite($stdout, $data);
2323

2424
// nothing could be written despite being writable => closed
2525
if ($r === 0) {
26-
Loop::get()->removeWriteStream($stdout);
26+
Loop::removeWriteStream($stdout);
2727
fclose($stdout);
2828
stream_set_blocking($stdout, true);
2929
fwrite(STDERR, 'Stopped because STDOUT closed' . PHP_EOL);
@@ -38,4 +38,4 @@
3838
}
3939
});
4040

41-
Loop::get()->run();
41+
Loop::run();

examples/13-http-client-blocking.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@
1616
fwrite($stream, "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n");
1717

1818
// wait for HTTP response
19-
Loop::get()->addReadStream($stream, function ($stream) {
19+
Loop::addReadStream($stream, function ($stream) {
2020
$chunk = fread($stream, 64 * 1024);
2121

2222
// reading nothing means we reached EOF
2323
if ($chunk === '') {
2424
echo '[END]' . PHP_EOL;
25-
Loop::get()->removeReadStream($stream);
25+
Loop::removeReadStream($stream);
2626
fclose($stream);
2727
return;
2828
}
2929

3030
echo $chunk;
3131
});
3232

33-
Loop::get()->run();
33+
Loop::run();

examples/14-http-client-async.php

+7-7
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323

2424
// print progress every 10ms
2525
echo 'Connecting';
26-
$timer = Loop::get()->addPeriodicTimer(0.01, function () {
26+
$timer = Loop::addPeriodicTimer(0.01, function () {
2727
echo '.';
2828
});
2929

3030
// wait for connection success/error
31-
Loop::get()->addWriteStream($stream, function ($stream) use ($timer) {
32-
Loop::get()->removeWriteStream($stream);
33-
Loop::get()->cancelTimer($timer);
31+
Loop::addWriteStream($stream, function ($stream) use ($timer) {
32+
Loop::removeWriteStream($stream);
33+
Loop::cancelTimer($timer);
3434

3535
// check for socket error (connection rejected)
3636
if (stream_socket_get_name($stream, true) === false) {
@@ -44,13 +44,13 @@
4444
fwrite($stream, "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n");
4545

4646
// wait for HTTP response
47-
Loop::get()->addReadStream($stream, function ($stream) {
47+
Loop::addReadStream($stream, function ($stream) {
4848
$chunk = fread($stream, 64 * 1024);
4949

5050
// reading nothing means we reached EOF
5151
if ($chunk === '') {
5252
echo '[END]' . PHP_EOL;
53-
Loop::get()->removeReadStream($stream);
53+
Loop::removeReadStream($stream);
5454
fclose($stream);
5555
return;
5656
}
@@ -59,4 +59,4 @@
5959
});
6060
});
6161

62-
Loop::get()->run();
62+
Loop::run();

0 commit comments

Comments
 (0)