Skip to content

Commit 961bef5

Browse files
committed
Add support for react/promise v3
With v3 come a whole list of [changes](https://github.com/reactphp/promise/releases/tag/v3.0.0) including end of promise chain detection, the removal of the `CancellablePromiseInterface` interface, and type templating.
1 parent 2a2c228 commit 961bef5

File tree

12 files changed

+112
-18
lines changed

12 files changed

+112
-18
lines changed

.github/workflows/ci.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,27 @@ jobs:
2929
coverage: xdebug
3030
- run: composer install
3131
- run: vendor/bin/phpunit --coverage-text
32+
PHPStan:
33+
name: PHPStan (PHP ${{ matrix.php }} on ${{ matrix.os }})
34+
runs-on: ${{ matrix.os }}
35+
strategy:
36+
fail-fast: false
37+
matrix:
38+
os:
39+
- ubuntu-20.04
40+
- windows-2019
41+
php:
42+
- 8.2
43+
- 8.1
44+
- 8.0
45+
- 7.4
46+
- 7.3
47+
- 7.2
48+
steps:
49+
- uses: actions/checkout@v3
50+
- uses: shivammathur/setup-php@v2
51+
with:
52+
php-version: ${{ matrix.php }}
53+
coverage: none
54+
- run: composer install
55+
- run: vendor/bin/phpstan

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@
2121
],
2222
"require": {
2323
"php": ">=7.0.0",
24-
"react/promise": "~2.2"
24+
"react/promise": "^3 || ~2.2"
2525
},
2626
"require-dev": {
2727
"satooshi/php-coveralls": "~1.0",
2828
"phpunit/phpunit": "^8.5 || ^9",
29-
"react/event-loop": "^1.0 || ^0.5 || ^0.4.2"
29+
"react/event-loop": "^1.0 || ^0.5 || ^0.4.2",
30+
"phpstan/phpstan": "^1.10"
3031
},
3132
"suggest": {
3233
"react/event-loop": "Used for scheduling async operations"

phpstan.neon.dist

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
parameters:
2+
level: max
3+
4+
paths:
5+
- test/types/
6+
7+
fileExtensions:
8+
- php

src/Observable.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@
7878
use Rx\Subject\ReplaySubject;
7979
use Rx\Subject\Subject;
8080

81+
/**
82+
* @template T
83+
* @template-implements ObservableInterface<T>
84+
*/
8185
abstract class Observable implements ObservableInterface
8286
{
8387
/**
@@ -296,25 +300,25 @@ public function mergeAll(): Observable
296300
/**
297301
* Converts an array to an observable sequence
298302
*
299-
* @param array $array
303+
* @param array<T> $array
300304
* @param SchedulerInterface $scheduler
301-
* @return ArrayObservable
305+
* @return ObservableInterface<T>
302306
*
303307
* @demo fromArray/fromArray.php
304308
* @operator
305309
* @reactivex from
306310
*/
307-
public static function fromArray(array $array, SchedulerInterface $scheduler = null): ArrayObservable
311+
public static function fromArray(array $array, SchedulerInterface $scheduler = null): ObservableInterface
308312
{
309313
return new ArrayObservable($array, $scheduler ?: Scheduler::getDefault());
310314
}
311315

312316
/**
313317
* Converts an Iterator into an observable sequence
314318
*
315-
* @param \Iterator $iterator
319+
* @param \Iterator<T> $iterator
316320
* @param SchedulerInterface $scheduler
317-
* @return IteratorObservable
321+
* @return ObservableInterface<T>
318322
*
319323
* @demo iterator/iterator.php
320324
* @operator
@@ -2049,8 +2053,8 @@ public function finally(callable $callback): Observable
20492053
/**
20502054
* Converts a promise into an observable
20512055
*
2052-
* @param PromiseInterface $promise
2053-
* @return Observable
2056+
* @param PromiseInterface<T> $promise
2057+
* @return Observable<T>
20542058
* @throws \InvalidArgumentException
20552059
*
20562060
* @demo promise/fromPromise.php

src/Observable/ArrayObservable.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,26 @@
66

77
use Rx\DisposableInterface;
88
use Rx\Observable;
9+
use Rx\ObservableInterface;
910
use Rx\ObserverInterface;
1011
use Rx\SchedulerInterface;
1112

13+
/**
14+
* @template T
15+
* @template-implements ObservableInterface<T>
16+
*/
1217
class ArrayObservable extends Observable
1318
{
19+
/**
20+
* @var array<T>
21+
*/
1422
private $data;
1523

1624
private $scheduler;
1725

26+
/**
27+
* @param array<T> $data
28+
*/
1829
public function __construct(array $data, SchedulerInterface $scheduler)
1930
{
2031
$this->data = $data;

src/Observable/IteratorObservable.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66

77
use Rx\DisposableInterface;
88
use Rx\Observable;
9+
use Rx\ObservableInterface;
910
use Rx\ObserverInterface;
1011
use Rx\SchedulerInterface;
1112

13+
/**
14+
* @template T
15+
* @template-implements ObservableInterface<T>
16+
*/
1217
class IteratorObservable extends Observable
1318
{
1419
private $items;

src/ObservableInterface.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace Rx;
66

7+
/**
8+
* @template-covariant T
9+
*/
710
interface ObservableInterface
811
{
912
/**

src/React/Promise.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace Rx\React;
44

5-
use React\Promise\CancellablePromiseInterface;
65
use React\Promise\Promise as ReactPromise;
76
use React\Promise\PromiseInterface;
87
use Rx\Disposable\CallbackDisposable;
@@ -11,12 +10,16 @@
1110
use Rx\Observable\AnonymousObservable;
1211
use Rx\Subject\AsyncSubject;
1312
use React\Promise\Deferred;
13+
use Throwable;
1414

15+
/**
16+
* @template T
17+
*/
1518
final class Promise
1619
{
1720
/**
18-
* @param mixed $value
19-
* @return ReactPromise A promise resolved to $value
21+
* @param T $value
22+
* @return PromiseInterface<T> A promise resolved to $value
2023
*/
2124
public static function resolved($value): ReactPromise
2225
{
@@ -27,21 +30,21 @@ public static function resolved($value): ReactPromise
2730

2831
/**
2932
* @param mixed $exception
30-
* @return ReactPromise A promise rejected with $exception
33+
* @return PromiseInterface<never> A promise rejected with $exception
3134
*/
3235
public static function rejected($exception): ReactPromise
3336
{
3437
$d = new Deferred();
35-
$d->reject($exception);
38+
$d->reject($exception instanceof Throwable ? $exception : new RejectedPromiseException($exception));
3639
return $d->promise();
3740
}
3841

3942
/**
4043
* Converts an existing observable sequence to React Promise
4144
*
42-
* @param ObservableInterface $observable
45+
* @param ObservableInterface<T> $observable
4346
* @param Deferred $deferred
44-
* @return ReactPromise
47+
* @return ReactPromise<T>
4548
* @throws \InvalidArgumentException
4649
*/
4750
public static function fromObservable(ObservableInterface $observable, Deferred $deferred = null): ReactPromise
@@ -94,7 +97,7 @@ function ($error) use ($subject) {
9497
$disp = $subject->subscribe($observer);
9598
return new CallbackDisposable(function () use ($p, $disp) {
9699
$disp->dispose();
97-
if ($p instanceof CancellablePromiseInterface) {
100+
if (\method_exists($p, 'cancel')) {
98101
$p->cancel();
99102
}
100103
});

test/Rx/Functional/Promise/FromPromiseTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function () {
4040
*/
4141
public function from_promise_failure()
4242
{
43-
$p = \React\Promise\reject('error');
43+
$p = \React\Promise\reject(new RejectedPromiseException('error'));
4444

4545
$source = Observable::fromPromise($p);
4646

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
use Rx\Observable;
4+
use Rx\Observable\ArrayObservable;
5+
use Rx\Scheduler\ImmediateScheduler;
6+
use function PHPStan\Testing\assertType;
7+
use function React\Promise\resolve;
8+
9+
assertType('Rx\ObservableInterface<bool>', Observable::fromPromise(resolve(false)));
10+
assertType('Rx\Observable\ArrayObservable<bool>', Observable::fromPromise(resolve(false)));
11+
assertType('Rx\Observable<bool>', Observable::fromPromise(resolve(false)));

0 commit comments

Comments
 (0)