Skip to content

Commit f129a5b

Browse files
committed
Automatically run Loop at end of program (autorun)
1 parent 81d17c1 commit f129a5b

19 files changed

+133
-40
lines changed

README.md

+23-12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ single [`run()`](#run) call that is controlled by the user.
1515
* [Usage](#usage)
1616
* [Loop](#loop)
1717
* [Loop methods](#loop-methods)
18+
* [Loop autorun](#loop-autorun)
1819
* [get()](#get)
1920
* [~~Factory~~](#factory)
2021
* [~~create()~~](#create)
@@ -76,8 +77,6 @@ Loop::addPeriodicTimer(5, function () {
7677
$formatted = number_format($memory, 3).'K';
7778
echo "Current memory usage: {$formatted}\n";
7879
});
79-
80-
Loop::run();
8180
```
8281

8382
See also the [examples](examples).
@@ -98,8 +97,6 @@ Loop::addTimer(1.0, function () use ($timer) {
9897
Loop::cancelTimer($timer);
9998
echo 'Done' . PHP_EOL;
10099
});
101-
102-
Loop::run();
103100
```
104101

105102
As an alternative, you can also explicitly create an event loop instance at the
@@ -127,12 +124,13 @@ In both cases, the program would perform the exact same steps.
127124
1. The event loop instance is created at the beginning of the program. This is
128125
implicitly done the first time you call the [`Loop` class](#loop) or
129126
explicitly when using the deprecated [`Factory::create() method`](#create)
130-
(or manually instantiating any of the [loop implementation](#loop-implementations)).
127+
(or manually instantiating any of the [loop implementations](#loop-implementations)).
131128
2. The event loop is used directly or passed as an instance to library and
132129
application code. In this example, a periodic timer is registered with the
133130
event loop which simply outputs `Tick` every fraction of a second until another
134131
timer stops the periodic timer after a second.
135-
3. The event loop is run at the end of the program with a single [`run()`](#run)
132+
3. The event loop is run at the end of the program. This is automatically done
133+
when using [`Loop` class](#loop) or explicitly with a single [`run()`](#run)
136134
call at the end of the program.
137135

138136
As of `v1.2.0`, we highly recommend using the [`Loop` class](#loop).
@@ -176,8 +174,6 @@ Loop::addTimer(1.0, function () use ($timer) {
176174
Loop::cancelTimer($timer);
177175
echo 'Done' . PHP_EOL;
178176
});
179-
180-
Loop::run();
181177
```
182178

183179
On the other hand, if you're familiar with object-oriented programming (OOP) and
@@ -208,14 +204,31 @@ class Greeter
208204
$greeter = new Greeter(Loop::get());
209205
$greeter->greet('Alice');
210206
$greeter->greet('Bob');
211-
212-
Loop::run();
213207
```
214208

215209
Each static method call will be forwarded as-is to the underlying event loop
216210
instance by using the [`Loop::get()`](#get) call internally.
217211
See [`LoopInterface`](#loopinterface) for more details about available methods.
218212

213+
#### Loop autorun
214+
215+
When using the `Loop` class, it will automatically execute the loop at the end of
216+
the program. This means the following example will schedule a timer and will
217+
automatically execute the program until the timer event fires:
218+
219+
```php
220+
use React\EventLoop\Loop;
221+
222+
Loop::addTimer(1.0, function () {
223+
echo 'Hello' . PHP_EOL;
224+
});
225+
```
226+
227+
As of `v1.2.0`, we highly recommend using the `Loop` class this way and omitting any
228+
explicit [`run()`](#run) calls. For BC reasons, the explicit [`run()`](#run)
229+
method is still valid and may still be useful in some applications, especially
230+
for a transition period towards the more concise style.
231+
219232
#### get()
220233

221234
The `get(): LoopInterface` method can be used to
@@ -262,8 +275,6 @@ class Greeter
262275
$greeter = new Greeter(Loop::get());
263276
$greeter->greet('Alice');
264277
$greeter->greet('Bob');
265-
266-
Loop::run();
267278
```
268279

269280
See [`LoopInterface`](#loopinterface) for more details about available methods.

examples/01-timers.php

-2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,3 @@
1111
Loop::addTimer(0.3, function () {
1212
echo 'hello ';
1313
});
14-
15-
Loop::run();

examples/02-periodic.php

-2
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,3 @@
1212
Loop::cancelTimer($timer);
1313
echo 'Done' . PHP_EOL;
1414
});
15-
16-
Loop::run();

examples/03-ticks.php

-2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,3 @@
1111
echo 'c';
1212
});
1313
echo 'a';
14-
15-
Loop::run();

examples/04-signals.php

-2
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,3 @@
1515
});
1616

1717
echo 'Listening for SIGINT. Use "kill -SIGINT ' . getmypid() . '" or CTRL+C' . PHP_EOL;
18-
19-
Loop::run();

examples/11-consume-stdin.php

-2
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,3 @@
2424

2525
echo strlen($chunk) . ' bytes' . PHP_EOL;
2626
});
27-
28-
Loop::run();

examples/12-generate-yes.php

-2
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,3 @@
3737
$data = substr($data, $r) . substr($data, 0, $r);
3838
}
3939
});
40-
41-
Loop::run();

examples/13-http-client-blocking.php

-2
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,3 @@
2929

3030
echo $chunk;
3131
});
32-
33-
Loop::run();

examples/14-http-client-async.php

-2
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,3 @@
5858
echo $chunk;
5959
});
6060
});
61-
62-
Loop::run();

examples/21-http-server.php

-2
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,3 @@
3232
$formatted = number_format($memory, 3).'K';
3333
echo "Current memory usage: {$formatted}\n";
3434
});
35-
36-
Loop::run();

examples/91-benchmark-ticks.php

-2
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,3 @@
99
for ($i = 0; $i < $n; ++$i) {
1010
Loop::futureTick(function () { });
1111
}
12-
13-
Loop::run();

examples/92-benchmark-timers.php

-2
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,3 @@
99
for ($i = 0; $i < $n; ++$i) {
1010
Loop::addTimer(0, function () { });
1111
}
12-
13-
Loop::run();

examples/93-benchmark-ticks-delay.php

-2
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,3 @@
1616
};
1717

1818
$tick();
19-
20-
Loop::run();

examples/94-benchmark-timers-delay.php

-2
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,3 @@
1616
};
1717

1818
$tick();
19-
20-
Loop::run();

src/Loop.php

+16-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ final class Loop
1212
*/
1313
private static $instance;
1414

15-
1615
/**
1716
* Returns the event loop.
1817
* When no loop is set it will it will call the factory to create one.
@@ -31,7 +30,22 @@ public static function get()
3130
return self::$instance;
3231
}
3332

34-
self::$instance = Factory::create();
33+
self::$instance = $loop = Factory::create();
34+
35+
// Automatically run loop at end of program, unless already started explicitly.
36+
// This is tested using child processes, so coverage is actually 100%, see BinTest.
37+
// @codeCoverageIgnoreStart
38+
$hasRun = false;
39+
$loop->futureTick(function () use (&$hasRun) {
40+
$hasRun = true;
41+
});
42+
43+
register_shutdown_function(function () use ($loop, &$hasRun) {
44+
if (!$hasRun) {
45+
$loop->run();
46+
}
47+
});
48+
// @codeCoverageIgnoreEnd
3549

3650
return self::$instance;
3751
}

tests/BinTest.php

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace React\Tests\EventLoop;
4+
5+
class BinTest extends TestCase
6+
{
7+
/**
8+
* @before
9+
*/
10+
public function setUpBin()
11+
{
12+
if (!defined('PHP_BINARY') || defined('HHVM_VERSION')) {
13+
$this->markTestSkipped('Tests not supported on legacy PHP 5.3 or HHVM');
14+
}
15+
16+
chdir(__DIR__ . '/bin/');
17+
}
18+
19+
public function testExecuteExampleWithoutLoopRunRunsLoopAndExecutesTicks()
20+
{
21+
$output = exec(escapeshellarg(PHP_BINARY) . ' 01-ticks-loop-class.php');
22+
23+
$this->assertEquals('abc', $output);
24+
}
25+
26+
public function testExecuteExampleWithExplicitLoopRunRunsLoopAndExecutesTicks()
27+
{
28+
$output = exec(escapeshellarg(PHP_BINARY) . ' 02-ticks-loop-instance.php');
29+
30+
$this->assertEquals('abc', $output);
31+
}
32+
33+
public function testExecuteExampleWithExplicitLoopRunAndStopRunsLoopAndExecutesTicksUntilStopped()
34+
{
35+
$output = exec(escapeshellarg(PHP_BINARY) . ' 03-ticks-loop-stop.php');
36+
37+
$this->assertEquals('abc', $output);
38+
}
39+
}

tests/bin/01-ticks-loop-class.php

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use React\EventLoop\Loop;
4+
5+
require __DIR__ . '/../../vendor/autoload.php';
6+
7+
Loop::futureTick(function () {
8+
echo 'b';
9+
});
10+
Loop::futureTick(function () {
11+
echo 'c';
12+
});
13+
echo 'a';

tests/bin/02-ticks-loop-instance.php

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
use React\EventLoop\Loop;
4+
5+
require __DIR__ . '/../../vendor/autoload.php';
6+
7+
$loop = Loop::get();
8+
9+
$loop->futureTick(function () {
10+
echo 'b';
11+
});
12+
13+
$loop->futureTick(function () {
14+
echo 'c';
15+
});
16+
17+
echo 'a';
18+
19+
$loop->run();

tests/bin/03-ticks-loop-stop.php

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
use React\EventLoop\Loop;
4+
5+
require __DIR__ . '/../../vendor/autoload.php';
6+
7+
$loop = Loop::get();
8+
9+
$loop->futureTick(function () use ($loop) {
10+
echo 'b';
11+
12+
$loop->stop();
13+
14+
$loop->futureTick(function () {
15+
echo 'never';
16+
});
17+
});
18+
19+
echo 'a';
20+
21+
$loop->run();
22+
23+
echo 'c';

0 commit comments

Comments
 (0)