Skip to content

Commit da3412f

Browse files
committed
Don't run loop automatically when explicitly calling stop()
1 parent cd198af commit da3412f

File tree

5 files changed

+72
-3
lines changed

5 files changed

+72
-3
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,25 @@ explicit [`run()`](#run) calls. For BC reasons, the explicit [`run()`](#run)
223223
method is still valid and may still be useful in some applications, especially
224224
for a transition period towards the more concise style.
225225

226+
If you don't want the `Loop` to run automatically, you can either explicitly
227+
[`run()`](#run) or [`stop()`](#stop) it. This can be useful if you're using
228+
a global exception handler like this:
229+
230+
```php
231+
use React\EventLoop\Loop;
232+
233+
Loop::addTimer(10.0, function () {
234+
echo 'Never happens';
235+
});
236+
237+
set_exception_handler(function (Throwable $e) {
238+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
239+
Loop::stop();
240+
});
241+
242+
throw new RuntimeException('Demo');
243+
```
244+
226245
#### get()
227246

228247
The `get(): LoopInterface` method can be used to

src/Loop.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ final class Loop
1212
*/
1313
private static $instance;
1414

15+
/** @var bool */
16+
private static $stopped = false;
17+
1518
/**
1619
* Returns the event loop.
1720
* When no loop is set it will it will call the factory to create one.
@@ -32,22 +35,23 @@ public static function get()
3235

3336
self::$instance = $loop = Factory::create();
3437

35-
// Automatically run loop at end of program, unless already started explicitly.
38+
// Automatically run loop at end of program, unless already started or stopped explicitly.
3639
// This is tested using child processes, so coverage is actually 100%, see BinTest.
3740
// @codeCoverageIgnoreStart
3841
$hasRun = false;
3942
$loop->futureTick(function () use (&$hasRun) {
4043
$hasRun = true;
4144
});
4245

43-
register_shutdown_function(function () use ($loop, &$hasRun) {
46+
$stopped =& self::$stopped;
47+
register_shutdown_function(function () use ($loop, &$hasRun, &$stopped) {
4448
// Don't run if we're coming from a fatal error (uncaught exception).
4549
$error = error_get_last();
4650
if ((isset($error['type']) ? $error['type'] : 0) & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) {
4751
return;
4852
}
4953

50-
if (!$hasRun) {
54+
if (!$hasRun && !$stopped) {
5155
$loop->run();
5256
}
5357
});
@@ -215,6 +219,7 @@ public static function run()
215219
*/
216220
public static function stop()
217221
{
222+
self::$stopped = true;
218223
self::get()->stop();
219224
}
220225
}

tests/BinTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,22 @@ public function testExecuteExampleWithUndefinedVariableShouldNotRunLoop()
5454

5555
$this->assertLessThan(1.0, $time);
5656
}
57+
58+
public function testExecuteExampleWithExplicitStopShouldNotRunLoop()
59+
{
60+
$time = microtime(true);
61+
exec(escapeshellarg(PHP_BINARY) . ' 21-stop.php 2>/dev/null');
62+
$time = microtime(true) - $time;
63+
64+
$this->assertLessThan(1.0, $time);
65+
}
66+
67+
public function testExecuteExampleWithExplicitStopInExceptionHandlerShouldNotRunLoop()
68+
{
69+
$time = microtime(true);
70+
exec(escapeshellarg(PHP_BINARY) . ' 22-uncaught-stop.php 2>/dev/null');
71+
$time = microtime(true) - $time;
72+
73+
$this->assertLessThan(1.0, $time);
74+
}
5775
}

tests/bin/21-stop.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
use React\EventLoop\Loop;
4+
5+
require __DIR__ . '/../../vendor/autoload.php';
6+
7+
Loop::addTimer(10.0, function () {
8+
echo 'never';
9+
});
10+
11+
Loop::stop();

tests/bin/22-stop-uncaught.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
use React\EventLoop\Loop;
4+
5+
require __DIR__ . '/../../vendor/autoload.php';
6+
7+
Loop::addTimer(10.0, function () {
8+
echo 'never';
9+
});
10+
11+
set_exception_handler(function (Exception $e) {
12+
echo 'Uncaught error occured' . PHP_EOL;
13+
Loop::stop();
14+
});
15+
16+
throw new RuntimeException();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy