Skip to content

Commit d6aec8c

Browse files
davidwdanmbonneau
authored andcommitted
Static scheduler now uses factories (#154)
1 parent 6c0e138 commit d6aec8c

File tree

6 files changed

+133
-60
lines changed

6 files changed

+133
-60
lines changed

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ use Rx\Observable;
7272
use React\EventLoop\Factory;
7373
use Rx\Scheduler;
7474

75-
$loop = Factory::create();
76-
$scheduler = new Scheduler\EventLoopScheduler($loop);
75+
$loop = Factory::create();
7776

7877
//You only need to set the default scheduler once
79-
Scheduler::setDefault($scheduler);
78+
Scheduler::setDefaultFactory(function() use($loop){
79+
return new Scheduler\EventLoopScheduler($loop);
80+
});
8081

8182
Observable::interval(1000)
8283
->take(5)

demo/bootstrap.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ function () use ($prefix) { echo $prefix . "Complete!\n"; }
3939
$stdoutObserver = $createStdoutObserver();
4040

4141
$loop = Factory::create();
42-
Scheduler::setDefault(new Scheduler\EventLoopScheduler($loop));
42+
Scheduler::setDefaultFactory(function () use ($loop) {
43+
return new Scheduler\EventLoopScheduler($loop);
44+
});
4345
register_shutdown_function(function () use ($loop) {
4446
$loop->run();
4547
});

src/Scheduler.php

+27-25
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,31 @@ class Scheduler
1111
private static $default;
1212
private static $async;
1313
private static $immediate;
14+
private static $defaultFactory;
15+
private static $asyncFactory;
1416

1517
public static function getDefault(): SchedulerInterface
1618
{
1719
if (static::$default) {
1820
return static::$default;
1921
}
2022

21-
throw new \Exception(
22-
"Please set a default scheduler (for react: Scheduler::setDefault(new EventLoopScheduler(\$loop));"
23-
);
23+
if (static::$defaultFactory === null) {
24+
throw new \Exception('Please set a default scheduler factory');
25+
}
26+
27+
static::$default = call_user_func(static::$defaultFactory);
28+
29+
return static::$default;
2430
}
2531

26-
public static function setDefault(SchedulerInterface $scheduler)
32+
public static function setDefaultFactory(callable $factory)
2733
{
2834
if (static::$default !== null) {
29-
throw new \Exception("Scheduler can only be set once.");
35+
throw new \Exception("The default factory can not be set after the scheduler has been created");
3036
}
3137

32-
static::$default = $scheduler;
38+
static::$defaultFactory = $factory;
3339
}
3440

3541
public static function getAsync(): AsyncSchedulerInterface
@@ -38,38 +44,34 @@ public static function getAsync(): AsyncSchedulerInterface
3844
return static::$async;
3945
}
4046

41-
if (static::$default instanceof AsyncSchedulerInterface) {
47+
if (static::$asyncFactory === null && static::getDefault() instanceof AsyncSchedulerInterface) {
4248
static::$async = static::$default;
43-
4449
return static::$async;
4550
}
4651

47-
throw new \Exception(
48-
"Please set an async scheduler (for react: Scheduler::setAsync(new EventLoopScheduler(\$loop));"
49-
);
50-
}
51-
52-
public static function getImmediate(): ImmediateScheduler
53-
{
54-
if (!static::$immediate) {
55-
static::$immediate = new ImmediateScheduler();
52+
if (static::$asyncFactory === null) {
53+
throw new \Exception('Please set an async scheduler factory');
5654
}
57-
return self::$immediate;
55+
56+
static::$async = call_user_func(static::$asyncFactory);
57+
58+
return static::$async;
5859
}
5960

60-
public static function setAsync(AsyncSchedulerInterface $async)
61+
public static function setAsyncFactory(callable $factory)
6162
{
6263
if (static::$async !== null) {
63-
throw new \Exception("Scheduler can only be set once.");
64+
throw new \Exception("The async factory can not be set after the scheduler has been created");
6465
}
65-
self::$async = $async;
66+
67+
static::$asyncFactory = $factory;
6668
}
6769

68-
public static function setImmediate(SchedulerInterface $immediate)
70+
public static function getImmediate(): ImmediateScheduler
6971
{
70-
if (static::$immediate !== null) {
71-
throw new \Exception("Scheduler can only be set once.");
72+
if (!static::$immediate) {
73+
static::$immediate = new ImmediateScheduler();
7274
}
73-
self::$immediate = $immediate;
75+
return self::$immediate;
7476
}
7577
}

test/Rx/SchedulerTest.php

+93-29
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class SchedulerTest extends TestCase
1313
private function resetStaticScheduler()
1414
{
1515
$ref = new \ReflectionClass(Scheduler::class);
16-
foreach (['default', 'async', 'immediate'] as $propertyName) {
16+
foreach (['default', 'async', 'immediate', 'defaultFactory', 'asyncFactory'] as $propertyName) {
1717
$prop = $ref->getProperty($propertyName);
1818
$prop->setAccessible(true);
1919
$prop->setValue(null);
@@ -28,7 +28,7 @@ public function setup()
2828

2929
/**
3030
* @expectedException \Exception
31-
* @expectedExceptionMessage Please set a default scheduler (for react: Scheduler::setDefault(new EventLoopScheduler($loop));
31+
* @expectedExceptionMessage Please set a default scheduler factory
3232
*/
3333
public function testGetDefaultThrowsIfNotSet()
3434
{
@@ -41,88 +41,152 @@ public function testSetDefault()
4141
{
4242
$scheduler = new TestScheduler();
4343

44-
Scheduler::setDefault($scheduler);
44+
Scheduler::setDefaultFactory(function () use ($scheduler) {
45+
return $scheduler;
46+
});
4547

4648
$this->assertSame($scheduler, Scheduler::getDefault());
4749
}
4850

51+
public function testSetDefaultTwiceBeforeGet()
52+
{
53+
$scheduler = new TestScheduler();
54+
55+
Scheduler::setDefaultFactory(function () use ($scheduler) {
56+
return $scheduler;
57+
});
58+
59+
$scheduler2 = new TestScheduler();
60+
61+
Scheduler::setDefaultFactory(function () use ($scheduler2) {
62+
return $scheduler2;
63+
});
64+
65+
$this->assertSame($scheduler2, Scheduler::getDefault());
66+
}
67+
4968
public function testSetAsync()
5069
{
5170
$scheduler = new TestScheduler();
5271

53-
Scheduler::setAsync($scheduler);
72+
Scheduler::setAsyncFactory(function () use ($scheduler) {
73+
return $scheduler;
74+
});
5475

5576
$this->assertSame($scheduler, Scheduler::getAsync());
5677
}
5778

58-
public function testSetImmediate()
79+
public function testSetAsyncTwiceBeforeGet()
5980
{
60-
$scheduler = new ImmediateScheduler();
81+
$scheduler = new TestScheduler();
82+
83+
Scheduler::setAsyncFactory(function () use ($scheduler) {
84+
return $scheduler;
85+
});
6186

62-
Scheduler::setImmediate($scheduler);
87+
$scheduler2 = new TestScheduler();
6388

64-
$this->assertSame($scheduler, Scheduler::getImmediate());
89+
Scheduler::setAsyncFactory(function () use ($scheduler2) {
90+
return $scheduler2;
91+
});
92+
93+
$this->assertSame($scheduler2, Scheduler::getAsync());
6594
}
6695

6796
/**
6897
* @expectedException \Exception
6998
*/
70-
public function testSetDefaultAfterDefaultStartThrowsException()
99+
public function testSetDefaultTwiceThrowsException()
71100
{
72101
$scheduler = new TestScheduler();
73102

74-
Scheduler::setDefault($scheduler);
103+
Scheduler::setDefaultFactory(function () use ($scheduler) {
104+
return $scheduler;
105+
});
75106

76-
$scheduler->start();
107+
Scheduler::getDefault();
77108

78-
$scheduler2 = new TestScheduler();
79-
80-
Scheduler::setDefault($scheduler2);
109+
Scheduler::setDefaultFactory(function () use ($scheduler) {
110+
return $scheduler;
111+
});
81112
}
82113

114+
83115
/**
84116
* @expectedException \Exception
85117
*/
86118
public function testSetAsyncTwiceThrowsException()
87119
{
88120
$scheduler = new TestScheduler();
89121

90-
Scheduler::setAsync($scheduler);
122+
Scheduler::setAsyncFactory(function () use ($scheduler) {
123+
return $scheduler;
124+
});
91125

92-
$scheduler2 = new TestScheduler();
126+
Scheduler::getAsync();
93127

94-
Scheduler::setAsync($scheduler2);
128+
Scheduler::setAsyncFactory(function () use ($scheduler) {
129+
return $scheduler;
130+
});
95131
}
96132

97133
/**
98134
* @expectedException \Exception
135+
* @expectedExceptionMessage Please set a default scheduler factory
99136
*/
100-
public function testSetImmediateTwiceThrowsException()
137+
public function testGetAsyncBeforeSet()
101138
{
102-
$scheduler = new ImmediateScheduler();
139+
Scheduler::getAsync();
140+
}
103141

104-
Scheduler::setImmediate($scheduler);
142+
public function testGetAsyncAfterSettingDefaultToAsync()
143+
{
144+
$asyncScheduler = new EventLoopScheduler(function () {
145+
});
105146

106-
$scheduler2 = new ImmediateScheduler();
147+
Scheduler::setDefaultFactory(function () use ($asyncScheduler) {
148+
return $asyncScheduler;
149+
});
107150

108-
Scheduler::setImmediate($scheduler2);
151+
$this->assertSame($asyncScheduler, Scheduler::getAsync());
109152
}
110153

111154
/**
112-
* @expectedException \Exception
113-
* @expectedExceptionMessage Please set an async scheduler (for react: Scheduler::setAsync(new EventLoopScheduler($loop));
155+
* @expectedException \Throwable
156+
* @expectedExceptionMessage Return value of Rx\Scheduler::getAsync() must implement interface Rx\AsyncSchedulerInterface, instance of Rx\Scheduler\ImmediateScheduler returned
114157
*/
115-
public function testGetAsyncBeforeSet()
158+
public function testAsyncSchedulerFactorReturnsNonAsyncScheduler()
116159
{
160+
Scheduler::setAsyncFactory(function () {
161+
return new ImmediateScheduler();
162+
});
163+
117164
Scheduler::getAsync();
118165
}
119166

120-
public function testGetAsyncAfterSettingDefaultToAsync()
167+
/**
168+
* @expectedException \Throwable
169+
* @expectedExceptionMessage Return value of Rx\Scheduler::getDefault() must implement interface Rx\SchedulerInterface, instance of stdClass returned
170+
*/
171+
public function testDefaultSchedulerFactorReturnsNonScheduler()
121172
{
122-
$asyncScheduler = new EventLoopScheduler(function () {});
173+
Scheduler::setDefaultFactory(function () {
174+
return new \stdClass();
175+
});
123176

124-
Scheduler::setDefault($asyncScheduler);
177+
Scheduler::getDefault();
178+
}
125179

126-
$this->assertSame($asyncScheduler, Scheduler::getAsync());
180+
/**
181+
* @expectedException \Throwable
182+
* @expectedExceptionMessage Please set an async scheduler factory
183+
*/
184+
public function testAsyncSchedulerFactorThrowsNonAsyncDefaultScheduler()
185+
{
186+
Scheduler::setDefaultFactory(function () {
187+
return new ImmediateScheduler();
188+
});
189+
190+
Scheduler::getAsync();
127191
}
128192
}

test/bootstrap.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
* The default scheduler is the EventLoopScheduler, which is asynchronous.
2222
* For testing we need to block at `subscribe`, so we need to switch the default to the ImmediateScheduler.
2323
*/
24-
\Rx\Scheduler::setDefault(new \Rx\Scheduler\ImmediateScheduler());
24+
\Rx\Scheduler::setDefaultFactory(function () {
25+
return new \Rx\Scheduler\ImmediateScheduler();
26+
});
2527

2628
require 'loop-auto-start.php';

test/loop-auto-start.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
$loop = Factory::create();
99
$scheduler = new Scheduler\EventLoopScheduler($loop);
10-
Scheduler::setAsync($scheduler);
10+
Scheduler::setAsyncFactory(function () use ($scheduler) {
11+
return $scheduler;
12+
});
1113

1214
register_shutdown_function(function () use ($loop) {
1315
$loop->run();

0 commit comments

Comments
 (0)