Skip to content

Commit eef0298

Browse files
committed
Add static Loop methods
1 parent 61977fc commit eef0298

17 files changed

+515
-86
lines changed

README.md

+164-36
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,88 +53,215 @@ 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:
8485

8586
```php
86-
// [1]
87-
$loop = React\EventLoop\Factory::create();
87+
use React\EventLoop\Loop;
8888

89-
// [2]
90-
$loop->addPeriodicTimer(1, function () {
91-
echo "Tick\n";
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;
9295
});
9396

94-
$stream = new React\Stream\ReadableResourceStream(
95-
fopen('file.txt', 'r'),
96-
$loop
97-
);
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:
103+
104+
```php
105+
$loop = React\EventLoop\Loop::get(); // or deprecated React\EventLoop\Factory::create();
106+
107+
$timer = $loop->addPeriodicTimer(0.1, function () {
108+
echo "Tick" . PHP_EOL;
109+
});
110+
$loop->addTimer(1.0, function () use ($loop, $timer) {
111+
$loop->cancelTimer($timer);
112+
echo 'Done' . PHP_EOL;
113+
});
98114

99-
// [3]
100115
$loop->run();
101116
```
102117

103-
1. The loop instance is created at the beginning of the program. A convenience
104-
factory [`React\EventLoop\Factory::create()`](#create) is provided by this library which
105-
picks the best available [loop implementation](#loop-implementations).
106-
2. The loop instance is used directly or passed to library and application code.
107-
In this example, a periodic timer is registered with the event loop which
108-
simply outputs `Tick` every second and a
109-
[readable stream](https://github.com/reactphp/stream#readableresourcestream)
110-
is created by using ReactPHP's
111-
[stream component](https://github.com/reactphp/stream) for demonstration
112-
purposes.
113-
3. The loop is run with a single [`$loop->run()`](#run) call at the end of the program.
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+
121+
1. The event loop instance is created at the beginning of the program. This is
122+
implicitly done the first time you call the [`Loop` class](#loop) or
123+
explicitly when using the deprecated [`Factory::create() method`](#create)
124+
(or manually instantiating any of the [loop implementation](#loop-implementations)).
125+
2. The event loop is used directly or passed as an instance to library and
126+
application code. In this example, a periodic timer is registered with the
127+
event loop which simply outputs `Tick` every fraction of a second until another
128+
timer stops the periodic timer after a second.
129+
3. The event loop is run at the end of the program with a single [`run()`](#run)
130+
call at the end of the program.
131+
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.
114135

115136
### Loop
116137

117138
The `Loop` class exists as a convenient global accessor for the event loop.
118139

119-
#### get()
140+
#### Loop methods
120141

121-
The `get(): LoopInterface` method is the preferred way to get and use the event loop. With
122-
it there is no need to always pass the loop around anymore.
142+
The `Loop` class provides all methods that exist on the [`LoopInterface`](#loopinterface)
143+
as static methods:
144+
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:
123161

124162
```php
125163
use React\EventLoop\Loop;
126164

127-
Loop::get()->addTimer(0.02, function () {
128-
echo 'World!';
165+
$timer = Loop::addPeriodicTimer(0.1, function () {
166+
echo 'tick!' . PHP_EOL;
129167
});
130-
Loop::get()->addTimer(0.01, function () {
131-
echo 'Hello ';
168+
169+
Loop::addTimer(1.0, function () use ($timer) {
170+
Loop::cancelTimer($timer);
171+
echo 'Done' . PHP_EOL;
132172
});
133173

134-
Loop::get()->run();
174+
Loop::run();
135175
```
136176

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+
Each static method call will be forwarded as-is to the underlying event loop
210+
instance by using the [`Loop::get()`](#get) call internally.
211+
See [`LoopInterface`](#loopinterface) for more details about available methods.
212+
213+
#### get()
214+
215+
The `get(): LoopInterface` method can be used to
216+
get the currently active event loop instance.
217+
218+
This method will always return the same event loop instance throughout the
219+
lifetime of your application.
220+
221+
```php
222+
use React\EventLoop\Loop;
223+
use React\EventLoop\LoopInterface;
224+
225+
$loop = Loop::get();
226+
227+
assert($loop instanceof LoopInterface);
228+
assert($loop === Loop::get());
229+
```
230+
231+
This is particularly useful if you're using object-oriented programming (OOP)
232+
and dependency injection (DI). In this case, you may want to inject an event
233+
loop instance and invoke instance methods on the `LoopInterface` like this:
234+
235+
```php
236+
use React\EventLoop\Loop;
237+
use React\EventLoop\LoopInterface;
238+
239+
class Greeter
240+
{
241+
private $loop;
242+
243+
public function __construct(LoopInterface $loop)
244+
{
245+
$this->loop = $loop;
246+
}
247+
248+
public function greet(string $name)
249+
{
250+
$this->loop->addTimer(1.0, function () use ($name) {
251+
echo 'Hello ' . $name . '!' . PHP_EOL;
252+
});
253+
}
254+
}
255+
256+
$greeter = new Greeter(Loop::get());
257+
$greeter->greet('Alice');
258+
$greeter->greet('Bob');
259+
260+
Loop::run();
261+
```
262+
263+
See [`LoopInterface`](#loopinterface) for more details about available methods.
264+
137265
### Factory
138266

139267
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();

0 commit comments

Comments
 (0)