From af34b8d80bc5792a5743d03fce21e563e5f75af0 Mon Sep 17 00:00:00 2001 From: Cees-Jan Kiewiet Date: Mon, 7 Aug 2023 11:29:29 +0200 Subject: [PATCH] Add support template types --- .github/workflows/ci.yml | 26 ++ composer.json | 5 +- phpstan.neon.dist | 3 +- src/Disposable/BinaryDisposable.php | 10 +- src/Disposable/CallbackDisposable.php | 7 + src/Disposable/CompositeDisposable.php | 19 + src/Disposable/RefCountDisposable.php | 18 + src/Disposable/SerialDisposable.php | 5 +- src/Disposable/SingleAssignmentDisposable.php | 16 + src/DisposableInterface.php | 3 + src/Notification.php | 34 +- src/Notification/OnCompletedNotification.php | 11 +- src/Notification/OnErrorNotification.php | 11 +- src/Notification/OnNextNotification.php | 14 +- src/Observable.php | 357 ++++++++++-------- src/Observable/AnonymousObservable.php | 8 + src/Observable/ArrayObservable.php | 19 + src/Observable/ConnectableObservable.php | 13 +- src/Observable/EmptyObservable.php | 7 + src/Observable/ErrorObservable.php | 11 + src/Observable/ForkJoinObservable.php | 18 +- src/Observable/GroupedObservable.php | 22 ++ src/Observable/IntervalObservable.php | 7 + src/Observable/IteratorObservable.php | 12 +- src/Observable/MulticastObservable.php | 14 +- src/Observable/NeverObservable.php | 4 + src/Observable/RangeObservable.php | 13 + src/Observable/RefCountObservable.php | 10 +- src/Observable/ReturnObservable.php | 15 + src/Observable/TimerObservable.php | 10 + src/ObservableFactoryWrapper.php | 16 +- src/ObservableInterface.php | 5 +- src/Observer/AbstractObserver.php | 14 + src/Observer/AutoDetachObserver.php | 17 + src/Observer/CallbackObserver.php | 16 +- src/Observer/DoObserver.php | 16 +- src/Observer/ScheduledObserver.php | 11 + src/ObserverInterface.php | 11 + src/Operator/BufferWithCountOperator.php | 2 +- src/Operator/CatchErrorOperator.php | 7 +- src/Operator/CombineLatestOperator.php | 10 +- src/Operator/ConcatAllOperator.php | 10 +- src/Operator/ConcatMapOperator.php | 6 +- src/Operator/ConcatOperator.php | 7 +- src/Operator/CountOperator.php | 7 + src/Operator/DefaultIfEmptyOperator.php | 8 +- src/Operator/DeferOperator.php | 8 +- src/Operator/DelayOperator.php | 11 +- src/Operator/DistinctOperator.php | 8 +- src/Operator/DistinctUntilChangedOperator.php | 12 +- src/Operator/DoOnEachOperator.php | 12 +- src/Operator/FilterOperator.php | 3 + src/Operator/FinallyOperator.php | 5 +- src/Operator/GroupByUntilOperator.php | 25 ++ src/Operator/MapOperator.php | 4 + src/Operator/MaxOperator.php | 3 + src/Operator/MergeAllOperator.php | 1 + src/Operator/MinOperator.php | 3 + src/Operator/OperatorInterface.php | 4 + src/Operator/RaceOperator.php | 14 +- src/Operator/ReduceOperator.php | 12 +- src/Operator/RepeatOperator.php | 5 +- src/Operator/RepeatWhenOperator.php | 11 +- src/Operator/RetryOperator.php | 3 + src/Operator/RetryWhenOperator.php | 4 + src/Operator/ScanOperator.php | 12 +- src/Operator/SkipLastOperator.php | 8 +- src/Operator/SkipOperator.php | 3 + src/Operator/SkipUntilOperator.php | 9 + src/Operator/StartWithArrayOperator.php | 16 + src/Operator/SubscribeOnOperator.php | 3 + src/Operator/SwitchFirstOperator.php | 7 + src/Operator/TakeLastOperator.php | 7 +- src/Operator/TakeOperator.php | 3 + src/Operator/TakeUntilOperator.php | 9 + src/Operator/TakeWhileOperator.php | 9 + src/Operator/ThrottleOperator.php | 23 +- src/Operator/TimeoutOperator.php | 21 +- src/Operator/TimestampOperator.php | 8 +- src/Operator/ToArrayOperator.php | 5 +- src/Operator/WithLatestFromOperator.php | 8 +- src/Operator/ZipOperator.php | 13 +- src/React/Promise.php | 51 +-- src/React/PromiseFactory.php | 14 +- src/React/RejectedPromiseException.php | 6 +- src/Scheduler.php | 36 +- src/Scheduler/EventLoopScheduler.php | 15 + src/Scheduler/InternalPriorityQueue.php | 58 +++ src/Scheduler/PriorityQueue.php | 67 ++-- src/Scheduler/ScheduledItem.php | 52 ++- src/Scheduler/VirtualTimeScheduler.php | 35 +- src/SchedulerInterface.php | 8 +- src/Subject/AsyncSubject.php | 8 +- src/Subject/BehaviorSubject.php | 15 + src/Subject/InnerSubscriptionDisposable.php | 17 + src/Subject/ReplaySubject.php | 23 +- src/Subject/Subject.php | 45 ++- src/Testing/ColdObservable.php | 29 +- src/Testing/HotObservable.php | 25 +- src/Testing/MockObserver.php | 22 ++ src/Testing/Recorded.php | 27 +- src/Testing/Subscription.php | 23 +- src/Testing/TestScheduler.php | 31 +- src/Testing/TestSubject.php | 15 +- src/Timestamped.php | 13 +- .../Functional/Operator/GroupByUntilTest.php | 7 +- .../Functional/Subject/ReplaySubjectTest.php | 147 ++++++++ test/Rx/ObservableTest.php | 2 +- test/Rx/Scheduler/PriorityQueueTest.php | 11 +- test/types/array-observable.php | 10 + test/types/observable-from-array.php | 8 + test/types/observable-from-promise.php | 9 + test/types/observable-of.php | 13 + test/types/observable-to-promise.php | 11 + test/types/promise-to-observable.php | 10 + 115 files changed, 1679 insertions(+), 381 deletions(-) create mode 100644 src/Scheduler/InternalPriorityQueue.php create mode 100644 test/types/array-observable.php create mode 100644 test/types/observable-from-array.php create mode 100644 test/types/observable-from-promise.php create mode 100644 test/types/observable-of.php create mode 100644 test/types/observable-to-promise.php create mode 100644 test/types/promise-to-observable.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b98344d0..52e285fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ jobs: - ubuntu-20.04 - windows-2019 php: + - 8.3 - 8.2 - 8.1 - 8.0 @@ -29,3 +30,28 @@ jobs: coverage: xdebug - run: composer install - run: vendor/bin/phpunit --coverage-text + PHPStan: + name: PHPStan (PHP ${{ matrix.php }} on ${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-20.04 + - windows-2019 + php: + - 8.3 + - 8.2 + - 8.1 + - 8.0 + - 7.4 + - 7.3 + - 7.2 + steps: + - uses: actions/checkout@v3 + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + - run: composer install + - run: vendor/bin/phpstan diff --git a/composer.json b/composer.json index 79921091..0533c56c 100644 --- a/composer.json +++ b/composer.json @@ -21,12 +21,13 @@ ], "require": { "php": ">=7.0.0", - "react/promise": "^3 || ~2.2" + "react/promise": "^3" }, "require-dev": { "satooshi/php-coveralls": "~1.0", "phpunit/phpunit": "^8.5 || ^9", - "react/event-loop": "^1.0 || ^0.5 || ^0.4.2" + "react/event-loop": "^1.0 || ^0.5 || ^0.4.2", + "phpstan/phpstan": "^1.10" }, "suggest": { "react/event-loop": "Used for scheduling async operations" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 18ad3d5e..fd96258c 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,7 +2,8 @@ parameters: level: max paths: + - src/ - test/types/ fileExtensions: - - php \ No newline at end of file + - php diff --git a/src/Disposable/BinaryDisposable.php b/src/Disposable/BinaryDisposable.php index 2197cc5b..31d3aa7d 100644 --- a/src/Disposable/BinaryDisposable.php +++ b/src/Disposable/BinaryDisposable.php @@ -12,10 +12,10 @@ */ class BinaryDisposable implements DisposableInterface { - /** @var \Rx\DisposableInterface */ + /** @var ?\Rx\DisposableInterface */ private $first; - /** @var \Rx\DisposableInterface */ + /** @var ?\Rx\DisposableInterface */ private $second; /** @var bool */ @@ -23,8 +23,8 @@ class BinaryDisposable implements DisposableInterface /** * BinaryDisposable constructor. - * @param $first - * @param $second + * @param DisposableInterface $first + * @param DisposableInterface $second */ public function __construct(DisposableInterface $first, DisposableInterface $second) { @@ -40,7 +40,9 @@ public function dispose() $this->isDisposed = true; + /** @phpstan-ignore-next-line */ $this->first->dispose(); + /** @phpstan-ignore-next-line */ $this->second->dispose(); $this->first = null; diff --git a/src/Disposable/CallbackDisposable.php b/src/Disposable/CallbackDisposable.php index 0198b8d9..8a00f3dd 100644 --- a/src/Disposable/CallbackDisposable.php +++ b/src/Disposable/CallbackDisposable.php @@ -8,7 +8,14 @@ class CallbackDisposable implements DisposableInterface { + /** + * @var callable + */ private $action; + + /** + * @var bool + */ private $disposed = false; public function __construct(callable $action) diff --git a/src/Disposable/CompositeDisposable.php b/src/Disposable/CompositeDisposable.php index 3a6621bf..e72f31f9 100644 --- a/src/Disposable/CompositeDisposable.php +++ b/src/Disposable/CompositeDisposable.php @@ -8,9 +8,19 @@ class CompositeDisposable implements DisposableInterface { + /** + * @var array + */ private $disposables; + + /** + * @var bool + */ private $isDisposed = false; + /** + * @param array $disposables + */ public function __construct(array $disposables = []) { $this->disposables = $disposables; @@ -32,6 +42,9 @@ public function dispose() } } + /** + * @return void + */ public function add(DisposableInterface $disposable) { if ($this->isDisposed) { @@ -65,11 +78,17 @@ public function contains(DisposableInterface $disposable): bool return in_array($disposable, $this->disposables, true); } + /** + * @return int + */ public function count() { return count($this->disposables); } + /** + * @return void + */ public function clear() { $disposables = $this->disposables; diff --git a/src/Disposable/RefCountDisposable.php b/src/Disposable/RefCountDisposable.php index 59d0e67d..9f7b975d 100644 --- a/src/Disposable/RefCountDisposable.php +++ b/src/Disposable/RefCountDisposable.php @@ -8,9 +8,24 @@ class RefCountDisposable implements DisposableInterface { + /** + * @var int + */ private $count = 0; + + /** + * @var DisposableInterface + */ private $disposable; + + /** + * @var bool + */ private $isDisposed = false; + + /** + * @var bool + */ private $isPrimaryDisposed = false; public function __construct(DisposableInterface $disposable) @@ -32,6 +47,9 @@ public function dispose() } } + /** + * @return DisposableInterface + */ public function getDisposable() { if (!$this->isDisposed) { diff --git a/src/Disposable/SerialDisposable.php b/src/Disposable/SerialDisposable.php index 30f8e863..ae376de3 100644 --- a/src/Disposable/SerialDisposable.php +++ b/src/Disposable/SerialDisposable.php @@ -15,7 +15,7 @@ class SerialDisposable implements DisposableInterface /** @var bool */ private $isDisposed = false; - /** @var DisposableInterface */ + /** @var ?DisposableInterface */ private $disposable = null; public function dispose() @@ -34,7 +34,7 @@ public function dispose() } /** - * @return DisposableInterface + * @return ?DisposableInterface */ public function getDisposable() { @@ -43,6 +43,7 @@ public function getDisposable() /** * @param DisposableInterface $disposable + * @return void */ public function setDisposable(DisposableInterface $disposable) { diff --git a/src/Disposable/SingleAssignmentDisposable.php b/src/Disposable/SingleAssignmentDisposable.php index cbf5ddaa..a6ad5a9f 100644 --- a/src/Disposable/SingleAssignmentDisposable.php +++ b/src/Disposable/SingleAssignmentDisposable.php @@ -9,7 +9,14 @@ class SingleAssignmentDisposable implements DisposableInterface { + /** + * @var ?DisposableInterface + */ private $current; + + /** + * @var bool + */ private $isDisposed = false; public function dispose() @@ -27,6 +34,9 @@ public function dispose() } } + /** + * @return void + */ public function setDisposable(DisposableInterface $disposable = null) { if ($this->current) { @@ -42,11 +52,17 @@ public function setDisposable(DisposableInterface $disposable = null) } } + /** + * @return DisposableInterface|null + */ public function getDisposable() { return $this->current; } + /** + * @return bool + */ public function isDisposed() { return $this->isDisposed; diff --git a/src/DisposableInterface.php b/src/DisposableInterface.php index ab44819f..a5689134 100644 --- a/src/DisposableInterface.php +++ b/src/DisposableInterface.php @@ -6,5 +6,8 @@ interface DisposableInterface { + /** + * @return void + */ public function dispose(); } diff --git a/src/Notification.php b/src/Notification.php index 6e7d60cd..562e9ba2 100644 --- a/src/Notification.php +++ b/src/Notification.php @@ -9,17 +9,14 @@ */ abstract class Notification { - private $kind; - /** - * @param mixed $kind Kind of notification + * @template T + * @param (callable(T): void)|ObserverInterface $observerOrOnNext + * @param (callable(\Throwable): void) $onError + * @param (callable(): void) $onCompleted + * @return void */ - public function __construct($kind) - { - $this->kind = $kind; - } - - public function accept($observerOrOnNext, $onError = null, $onCompleted = null) + public function accept($observerOrOnNext, callable $onError = null, callable $onCompleted = null) { if (null === $onError && null === $onCompleted && $observerOrOnNext instanceof ObserverInterface) { $this->doAcceptObservable($observerOrOnNext); @@ -27,15 +24,30 @@ public function accept($observerOrOnNext, $onError = null, $onCompleted = null) return; } - return $this->doAccept($observerOrOnNext, $onError, $onCompleted); + assert(is_callable($observerOrOnNext)); + $this->doAccept($observerOrOnNext, $onError, $onCompleted); } + /** + * @param mixed $other + */ public function equals($other): bool { + /** @phpstan-ignore-next-line */ return (string)$this === (string)$other; } + /** + * @return void + */ abstract protected function doAcceptObservable(ObserverInterface $observer); - abstract protected function doAccept($onNext, $onError, $onCompleted); + /** + * @template T + * @param (callable(T): void) $onNext + * @param (callable(\Throwable): void) $onError + * @param (callable(): void) $onCompleted + * @return void + */ + abstract protected function doAccept(callable $onNext, callable $onError = null, callable $onCompleted = null); } diff --git a/src/Notification/OnCompletedNotification.php b/src/Notification/OnCompletedNotification.php index 102750d8..37658efe 100644 --- a/src/Notification/OnCompletedNotification.php +++ b/src/Notification/OnCompletedNotification.php @@ -9,18 +9,17 @@ class OnCompletedNotification extends Notification { - public function __construct() - { - parent::__construct('C'); - } - + /** + * @return void + */ protected function doAcceptObservable(ObserverInterface $observer) { $observer->onCompleted(); } - protected function doAccept($onNext, $onError, $onCompleted) + protected function doAccept(callable $onNext, callable $onError = null, callable $onCompleted = null) { + assert(is_callable($onCompleted)); $onCompleted(); } diff --git a/src/Notification/OnErrorNotification.php b/src/Notification/OnErrorNotification.php index c974ee1d..51d5df15 100644 --- a/src/Notification/OnErrorNotification.php +++ b/src/Notification/OnErrorNotification.php @@ -9,22 +9,27 @@ class OnErrorNotification extends Notification { + /** + * @var \Throwable + */ private $exception; public function __construct(\Throwable $exception) { - parent::__construct('E'); - $this->exception = $exception; } + /** + * @return void + */ protected function doAcceptObservable(ObserverInterface $observer) { $observer->onError($this->exception); } - protected function doAccept($onNext, $onError, $onCompleted) + protected function doAccept(callable $onNext, callable $onError = null, callable $onCompleted = null) { + assert(is_callable($onError)); $onError($this->exception); } diff --git a/src/Notification/OnNextNotification.php b/src/Notification/OnNextNotification.php index 57f5f946..1af00195 100644 --- a/src/Notification/OnNextNotification.php +++ b/src/Notification/OnNextNotification.php @@ -9,21 +9,28 @@ class OnNextNotification extends Notification { + /** + * @var mixed + */ private $value; + /** + * @param mixed $value + */ public function __construct($value) { - parent::__construct('N'); - $this->value = $value; } + /** + * @return void + */ protected function doAcceptObservable(ObserverInterface $observer) { $observer->onNext($this->value); } - protected function doAccept($onNext, $onError, $onCompleted) + protected function doAccept(callable $onNext, callable $onError = null, callable $onCompleted = null) { $onNext($this->value); } @@ -41,6 +48,7 @@ public function equals($other): bool } } + /** @phpstan-ignore-next-line */ return (string)$this === (string)$other; } } diff --git a/src/Observable.php b/src/Observable.php index 79db73ba..c99587c6 100644 --- a/src/Observable.php +++ b/src/Observable.php @@ -78,10 +78,14 @@ use Rx\Subject\ReplaySubject; use Rx\Subject\Subject; +/** + * @template T + * @template-implements ObservableInterface + */ abstract class Observable implements ObservableInterface { /** - * @param callable|ObserverInterface|null $onNextOrObserver + * @param (callable(T): void)|ObserverInterface|null $onNextOrObserver * @param callable|null $onError * @param callable|null $onCompleted * @return DisposableInterface @@ -94,7 +98,7 @@ public function subscribe($onNextOrObserver = null, callable $onError = null, ca { if ($onNextOrObserver instanceof ObserverInterface) { return $this->_subscribe($onNextOrObserver); - } elseif ($onNextOrObserver !== null && !is_callable($onNextOrObserver)) { + } elseif ($onNextOrObserver !== null && !is_callable($onNextOrObserver)) { /** @phpstan-ignore-line */ throw new \InvalidArgumentException('The first argument needs to be a "callable" or "Observer"'); } @@ -108,6 +112,7 @@ public function subscribe($onNextOrObserver = null, callable $onError = null, ca $onNextOrObserver($value); } catch (\Throwable $throwable) { $disposable->dispose(); + /** @phpstan-ignore-next-line */ $observer->onError($throwable); } }, @@ -145,7 +150,7 @@ public function subscribeCallback(callable $onNext = null, callable $onError = n * Creates an observable sequence from a specified subscribeAction callable implementation. * * @param callable $subscribeAction Implementation of the resulting observable sequence's subscribe method. - * @return Observable The observable sequence with the specified implementation for the subscribe method. + * @return Observable The observable sequence with the specified implementation for the subscribe method. * * @demo create/create.php * @operator @@ -160,8 +165,8 @@ public static function create(callable $subscribeAction): Observable * Returns an Observable that emits an infinite sequence of ascending integers starting at 0, with a constant interval of time of your choosing between emissions. * * @param $interval int Period for producing the values in the resulting sequence (specified as an integer denoting milliseconds). - * @param null|AsyncSchedulerInterface|SchedulerInterface $scheduler - * @return IntervalObservable An observable sequence that produces a value after each period. + * @param ?AsyncSchedulerInterface $scheduler + * @return IntervalObservable An observable sequence that produces a value after each period. * * @demo interval/interval.php * @operator @@ -175,15 +180,16 @@ public static function interval(int $interval, AsyncSchedulerInterface $schedule /** * Returns an observable sequence that contains a single element. * - * @param mixed $value Single element in the resulting observable sequence. - * @param SchedulerInterface $scheduler - * @return ReturnObservable An observable sequence with the single element. + * @template X + * @param X $value Single element in the resulting observable sequence. + * @param ?SchedulerInterface $scheduler + * @return Observable * * @demo of/of.php * @operator * @reactivex just */ - public static function of($value, SchedulerInterface $scheduler = null): ReturnObservable + public static function of($value, SchedulerInterface $scheduler = null): Observable { return new ReturnObservable($value, $scheduler ?: Scheduler::getDefault()); } @@ -192,11 +198,12 @@ public static function of($value, SchedulerInterface $scheduler = null): ReturnO * @deprecated Use `of` * Alias for of * - * @param $value + * @template X + * @param X $value * @param SchedulerInterface|null $scheduler - * @return ReturnObservable + * @return Observable */ - public static function just($value, SchedulerInterface $scheduler = null): ReturnObservable + public static function just($value, SchedulerInterface $scheduler = null): Observable { return static::of($value, $scheduler); } @@ -205,7 +212,7 @@ public static function just($value, SchedulerInterface $scheduler = null): Retur * Returns an empty observable sequence. * * @param SchedulerInterface $scheduler - * @return EmptyObservable An observable sequence with no elements. + * @return EmptyObservable An observable sequence with no elements. * * @demo empty/empty.php * @operator @@ -221,7 +228,7 @@ public static function empty(SchedulerInterface $scheduler = null): EmptyObserva * Alias for empty * * @param SchedulerInterface|null $scheduler - * @return EmptyObservable + * @return EmptyObservable */ public static function emptyObservable(SchedulerInterface $scheduler = null): EmptyObservable { @@ -231,7 +238,7 @@ public static function emptyObservable(SchedulerInterface $scheduler = null): Em /** * Returns a non-terminating observable sequence, which can be used to denote an infinite duration. * - * @return NeverObservable An observable sequence whose observers will never get called. + * @return NeverObservable An observable sequence whose observers will never get called. * * @demo never/never.php * @operator @@ -239,6 +246,7 @@ public static function emptyObservable(SchedulerInterface $scheduler = null): Em */ public static function never(): NeverObservable { + /** @phpstan-ignore-next-line */ return new NeverObservable(); } @@ -247,7 +255,7 @@ public static function never(): NeverObservable * * @param \Throwable $error * @param SchedulerInterface $scheduler - * @return ErrorObservable The observable sequence that terminates exceptionally with the specified exception object. + * @return ErrorObservable The observable sequence that terminates exceptionally with the specified exception object. * * @demo error-observable/error-observable.php * @operator @@ -261,8 +269,8 @@ public static function error(\Throwable $error, SchedulerInterface $scheduler = /** * Combine an Observable together with another Observable by merging their emissions into a single Observable. * - * @param ObservableInterface $otherObservable - * @return Observable + * @param ObservableInterface $otherObservable + * @return Observable * * @demo merge/merge.php * @operator @@ -280,7 +288,7 @@ public function merge(ObservableInterface $otherObservable): Observable /** * Merges an observable sequence of observables into an observable sequence. * - * @return Observable + * @return Observable * * @demo merge/merge-all.php * @operator @@ -289,22 +297,23 @@ public function merge(ObservableInterface $otherObservable): Observable public function mergeAll(): Observable { return $this->lift(function () { - return new MergeAllOperator($this); + return new MergeAllOperator(); }); } /** * Converts an array to an observable sequence * - * @param array $array - * @param SchedulerInterface $scheduler - * @return ArrayObservable + * @template X + * @param array $array + * @param ?SchedulerInterface $scheduler + * @return Observable * * @demo fromArray/fromArray.php * @operator * @reactivex from */ - public static function fromArray(array $array, SchedulerInterface $scheduler = null): ArrayObservable + public static function fromArray(array $array, SchedulerInterface $scheduler = null): Observable { return new ArrayObservable($array, $scheduler ?: Scheduler::getDefault()); } @@ -312,15 +321,15 @@ public static function fromArray(array $array, SchedulerInterface $scheduler = n /** * Converts an Iterator into an observable sequence * - * @param \Iterator $iterator + * @param \Iterator $iterator * @param SchedulerInterface $scheduler - * @return IteratorObservable + * @return Observable * * @demo iterator/iterator.php * @operator * @reactivex from */ - public static function fromIterator(\Iterator $iterator, SchedulerInterface $scheduler = null): IteratorObservable + public static function fromIterator(\Iterator $iterator, SchedulerInterface $scheduler = null): Observable { return new IteratorObservable($iterator, $scheduler ?: Scheduler::getDefault()); } @@ -328,9 +337,10 @@ public static function fromIterator(\Iterator $iterator, SchedulerInterface $sch /** * Returns an observable sequence that invokes the specified factory function whenever a new observer subscribes. * - * @param callable $factory + * @template X + * @param (callable(): (PromiseInterface|ObservableInterface)) $factory * @param SchedulerInterface $scheduler - * @return Observable + * @return Observable * * @demo defer/defer.php * @operator @@ -348,10 +358,10 @@ public static function defer(callable $factory, SchedulerInterface $scheduler = * Generates an observable sequence of integral numbers within a specified range, using the specified scheduler to * send out observer messages. * - * @param $start - * @param $count + * @param int $start + * @param int $count * @param SchedulerInterface $scheduler - * @return RangeObservable + * @return RangeObservable * @throws \InvalidArgumentException * * @demo range/range.php @@ -367,9 +377,10 @@ public static function range(int $start, int $count, SchedulerInterface $schedul * Invokes the specified function asynchronously on the specified scheduler, surfacing the result through an * observable sequence. * - * @param callable $action + * @template X + * @param (callable(): X) $action * @param SchedulerInterface $scheduler - * @return Observable + * @return Observable * * @demo start/start.php * @operator @@ -378,18 +389,18 @@ public static function range(int $start, int $count, SchedulerInterface $schedul public static function start(callable $action, SchedulerInterface $scheduler = null): Observable { $scheduler = $scheduler ?? Scheduler::getDefault(); + /** + * @var Subject $subject + */ $subject = new AsyncSubject(); $scheduler->schedule(function () use ($subject, $action) { - $result = null; try { - $result = $action(); + $subject->onNext($action()); + $subject->onCompleted(); } catch (\Throwable $e) { $subject->onError($e); - return; } - $subject->onNext($result); - $subject->onCompleted(); }); return $subject->asObservable(); @@ -399,7 +410,7 @@ public static function start(callable $action, SchedulerInterface $scheduler = n * Takes a transforming function that operates on each element. * * @param callable $selector - * @return Observable + * @return Observable * * @demo map/map.php * @operator @@ -416,7 +427,7 @@ public function map(callable $selector): Observable * Maps operator variant that calls the map selector with the index and value * * @param callable $selector - * @return Observable + * @return Observable * * @demo map/mapWithIndex.php * @operator @@ -433,8 +444,8 @@ public function mapWithIndex(callable $selector): Observable /** * Maps every value to the same value every time * - * @param $value - * @return Observable + * @param T $value + * @return Observable * * @demo map/mapTo.php * @operator @@ -451,7 +462,7 @@ public function mapTo($value): Observable * Alias for Map * * @param callable $selector - * @return Observable + * @return Observable * * @operator * @reactivex map @@ -465,7 +476,7 @@ public function select(callable $selector): Observable * Emit only those items from an Observable that pass a predicate test. * * @param callable $predicate - * @return Observable + * @return Observable * * @demo filter/filter.php * @operator @@ -482,7 +493,7 @@ public function filter(callable $predicate): Observable * Alias for filter * * @param callable $predicate - * @return Observable + * @return Observable * * @operator * @reactivex filter @@ -495,8 +506,8 @@ public function where(callable $predicate): Observable /** * Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences into one observable sequence. * - * @param callable $selector - * @return Observable + * @param (callable(): (PromiseInterface|ObservableInterface)) $selector + * @return Observable * * @demo flatMap/flatMap.php * @operator @@ -511,10 +522,10 @@ public function flatMap(callable $selector): Observable * Projects each element of the source observable sequence to the other observable sequence and merges the * resulting observable sequences into one observable sequence. * - * @param ObservableInterface $observable - An an observable sequence to project each element from the source + * @param ObservableInterface $observable - An an observable sequence to project each element from the source * sequence onto. * - * @return Observable + * @return Observable * * @demo concat/concatMapTo.php * @operator @@ -530,8 +541,8 @@ public function flatMapTo(ObservableInterface $observable): Observable /** * Alias for flatMap * - * @param $selector - * @return Observable + * @param (callable(): (PromiseInterface|ObservableInterface)) $selector + * @return Observable * * @operator * @reactivex flatMap @@ -554,7 +565,7 @@ public function selectMany($selector): Observable * new one. * * @param callable $selector - A transform function to apply to each source element. - * @return Observable - An observable sequence which transforms the items emitted by an Observable into + * @return Observable - An observable sequence which transforms the items emitted by an Observable into * Observables, and mirror those items emitted by the most-recently transformed Observable. * * @demo flatMap/flatMapLatest.php @@ -568,7 +579,7 @@ public function flatMapLatest(callable $selector): Observable /** * @param integer $count - * @return Observable + * @return Observable * * @demo skip/skip.php * @operator @@ -587,7 +598,7 @@ public function skip(int $count): Observable * * @param callable $predicate A function to test each element for a condition. * - * @return Observable An observable sequence that contains the elements from the input sequence starting + * @return Observable An observable sequence that contains the elements from the input sequence starting * at the first element in the linear series that does not pass the test specified by predicate. * * @demo skip/skipWhile.php @@ -608,7 +619,7 @@ public function skipWhile(callable $predicate): Observable * @param callable $predicate A function to test each element for a condition; the first parameter of the * function represents the index of the source element, the second parameter is the value. * - * @return Observable An observable sequence that contains the elements from the input sequence starting + * @return Observable An observable sequence that contains the elements from the input sequence starting * at the first element in the linear series that does not pass the test specified by predicate. * * @demo skip/skipWhileWithIndex.php @@ -627,7 +638,7 @@ public function skipWhileWithIndex(callable $predicate): Observable * Returns a specified number of contiguous elements from the start of an observable sequence * * @param integer $count - * @return Observable|EmptyObservable + * @return Observable|EmptyObservable * * @demo take/take.php * @operator @@ -647,9 +658,9 @@ public function take(int $count): Observable /** * Returns the values from the source observable sequence until the other observable sequence produces a value. * - * @param ObservableInterface $other - other Observable sequence that terminates propagation of elements of + * @param ObservableInterface $other - other Observable sequence that terminates propagation of elements of * the source sequence. - * @return Observable - An observable sequence containing the elements of the source sequence up to the + * @return Observable - An observable sequence containing the elements of the source sequence up to the * point the other sequence interrupted further propagation. * * @demo take/takeUntil.php @@ -669,7 +680,7 @@ public function takeUntil(ObservableInterface $other): Observable * element. * * @param callable $predicate - * @return Observable + * @return Observable * * @demo take/takeWhile.php * @operator @@ -688,7 +699,7 @@ public function takeWhile(callable $predicate): Observable * value of the element. * * @param callable $predicate - * @return Observable + * @return Observable * * @demo take/takeWhileWithIndex.php * @operator @@ -705,8 +716,8 @@ public function takeWhileWithIndex(callable $predicate): Observable /** * Returns a specified number of contiguous elements from the end of an observable sequence. * - * @param $count - * @return Observable + * @param int $count + * @return Observable * * @demo take/takeLast.php * @operator @@ -725,7 +736,7 @@ public function takeLast(int $count): Observable * @param callable $keySelector * @param callable|null $elementSelector * @param callable|null $keySerializer - * @return Observable + * @return Observable * * @demo groupBy/groupBy.php * @operator @@ -745,7 +756,7 @@ public function groupBy(callable $keySelector, callable $elementSelector = null, * @param callable|null $elementSelector * @param callable|null $durationSelector * @param callable|null $keySerializer - * @return Observable + * @return Observable * * @demo groupBy/groupByUntil.php * @operator @@ -763,7 +774,7 @@ public function groupByUntil(callable $keySelector, callable $elementSelector = * the values of the current Observable through the Operator function. * * @param callable $operatorFactory - * @return Observable + * @return Observable */ public function lift(callable $operatorFactory): Observable { @@ -780,9 +791,9 @@ public function lift(callable $operatorFactory): Observable * namespace format: * CustomNamespace\Rx\Operator\OperatorNameOperator * - * @param $name - * @param $arguments - * @return Observable + * @param string $name + * @param array $arguments + * @return Observable * * @demo custom-operator/rot13.php */ @@ -794,6 +805,9 @@ public function __call($name, array $arguments): Observable $name = $methodName; $fullNamespace = $namespace . '\\' . $fullNamespace; } + /** + * @var class-string + */ $className = $fullNamespace . ucfirst($name) . 'Operator'; return $this->lift(function () use ($className, $arguments) { @@ -808,7 +822,7 @@ public function __call($name, array $arguments): Observable * * @param callable $accumulator - An accumulator function to be invoked on each element. * @param mixed $seed [optional] - The initial accumulator value. - * @return Observable - An observable sequence containing a single element with the final + * @return Observable - An observable sequence containing a single element with the final * accumulator value. * * @demo reduce/reduce.php @@ -829,7 +843,7 @@ public function reduce(callable $accumulator, $seed = null): Observable * structure which can grow large. * * @param callable|null $comparer - * @return Observable + * @return Observable * * @demo distinct/distinct.php * @operator @@ -845,9 +859,9 @@ public function distinct(callable $comparer = null): Observable /** * Variant of distinct that takes a key selector * - * @param callable|null $keySelector + * @param callable $keySelector * @param callable|null $comparer - * @return Observable + * @return Observable * * @demo distinct/distinctKey.php * @operator @@ -864,7 +878,7 @@ public function distinctKey(callable $keySelector, callable $comparer = null): O * A variant of distinct that only compares emitted items from the source Observable against their immediate predecessors in order to determine whether or not they are distinct. * * @param callable $comparer - * @return Observable + * @return Observable * * @demo distinct/distinctUntilChanged.php * @operator @@ -883,7 +897,7 @@ public function distinctUntilChanged(callable $comparer = null): Observable * * @param callable $keySelector * @param callable $comparer - * @return Observable + * @return Observable * * @demo distinct/distinctUntilKeyChanged.php * @operator @@ -913,7 +927,7 @@ public function distinctUntilKeyChanged(callable $keySelector = null, callable $ * @param callable|ObserverInterface $onNextOrObserver * @param callable $onError * @param callable $onCompleted - * @return Observable + * @return Observable * @throws \InvalidArgumentException * * @demo do/do.php @@ -940,7 +954,7 @@ public function do($onNextOrObserver = null, callable $onError = null, callable * Alias for do * * @param ObserverInterface $observer - * @return mixed + * @return Observable */ public function doOnEach(ObserverInterface $observer): Observable { @@ -950,7 +964,7 @@ public function doOnEach(ObserverInterface $observer): Observable /** * @deprecated Use `do` * @param callable $onNext - * @return Observable + * @return Observable * * @demo do/doOnNext.php * @operator @@ -965,7 +979,7 @@ public function doOnNext(callable $onNext): Observable /** * @param callable $onError - * @return Observable + * @return Observable * * @demo do/doOnError.php * @operator @@ -981,7 +995,7 @@ public function doOnError(callable $onError): Observable /** * @param callable $onCompleted - * @return Observable + * @return Observable * * @demo do/doOnCompleted.php * @operator @@ -1000,9 +1014,9 @@ public function doOnCompleted(callable $onCompleted): Observable * Applies an accumulator function over an observable sequence and returns each intermediate result. * The optional seed value is used as the initial accumulator value. * - * @param $accumulator + * @param callable $accumulator * @param mixed $seed - * @return Observable + * @return Observable * * @demo scan/scan.php * @demo scan/scan-with-seed.php @@ -1019,7 +1033,7 @@ public function scan(callable $accumulator, $seed = null): Observable /** * Creates an observable sequence containing a single element which is an array containing all the elements of the source sequence. * - * @return Observable An observable sequence containing a single element with a list containing all the + * @return Observable An observable sequence containing a single element with a list containing all the * elements of the source sequence. * * @demo toArray/toArray.php @@ -1041,7 +1055,7 @@ public function toArray(): Observable * elements to be delayed. * * @param integer $count Number of elements to bypass at the end of the source sequence. - * @return Observable An observable sequence containing the source sequence elements except for the + * @return Observable An observable sequence containing the source sequence elements except for the * bypassed ones at the end. * * @demo skip/skipLast.php @@ -1058,8 +1072,8 @@ public function skipLast(int $count): Observable /** * Returns the values from the source observable sequence only after the other observable sequence produces a value. * - * @param mixed $other The observable sequence that triggers propagation of elements of the source sequence. - * @return Observable An observable sequence containing the elements of the source sequence starting + * @param ObservableInterface $other The observable sequence that triggers propagation of elements of the source sequence. + * @return Observable An observable sequence containing the elements of the source sequence starting * from the point the other sequence triggered propagation. * * @demo skip/skipUntil.php @@ -1078,7 +1092,7 @@ public function skipUntil(ObservableInterface $other): Observable * * @param integer $dueTime - milliseconds * @param AsyncSchedulerInterface $scheduler - * @return TimerObservable + * @return TimerObservable * * @demo timer/timer.php * @operator @@ -1092,7 +1106,7 @@ public static function timer(int $dueTime, AsyncSchedulerInterface $scheduler = /** * Hides the identity of an observable sequence. * - * @return Observable An observable sequence that hides the identity of the source sequence. + * @return Observable An observable sequence that hides the identity of the source sequence. * * @demo asObservable/asObservable.php * @operator @@ -1108,8 +1122,8 @@ public function asObservable(): Observable /** * Concatenate an observable sequence onto the end of the source observable. * - * @param ObservableInterface $observable - * @return Observable + * @param ObservableInterface $observable + * @return Observable * * @demo concat/concat.php * @operator @@ -1139,7 +1153,7 @@ public function concat(ObservableInterface $observable): Observable * - the index of the outer element * - the index of the inner element * - * @return Observable - An observable sequence whose elements are the result of invoking the one-to-many + * @return Observable - An observable sequence whose elements are the result of invoking the one-to-many * transform function collectionSelector on each element of the input sequence and then mapping each of those * sequence elements and their corresponding source element to a result element. * @@ -1158,7 +1172,7 @@ public function concatMap(callable $selector, callable $resultSelector = null): * Projects each element of the source observable sequence to the other observable sequence and merges the * resulting observable sequences into one observable sequence. * - * @param ObservableInterface $observable - An an observable sequence to project each element from the source + * @param ObservableInterface $observable - An an observable sequence to project each element from the source * sequence onto. * * @param callable $resultSelector A transform function to apply to each element of the intermediate sequence. @@ -1168,7 +1182,7 @@ public function concatMap(callable $selector, callable $resultSelector = null): * - the index of the outer element * - the index of the inner element * - * @return Observable An observable sequence whose elements are the result of invoking the one-to-many + * @return Observable An observable sequence whose elements are the result of invoking the one-to-many * transform function collectionSelector on each element of the input sequence and then mapping each of those * sequence elements and their corresponding source element to a result element. * @@ -1186,7 +1200,7 @@ public function concatMapTo(ObservableInterface $observable, callable $resultSel /** * Concatenates a sequence of observable sequences into a single observable sequence. * - * @return Observable The observable sequence that merges the elements of the inner sequences. + * @return Observable The observable sequence that merges the elements of the inner sequences. * * @demo concat/concatAll.php * @operator @@ -1204,7 +1218,7 @@ public function concatAll(): Observable * sequence satisfy a condition if provided, else the count of items. * * @param callable $predicate - * @return Observable + * @return Observable * * @demo count/count.php * @operator @@ -1223,9 +1237,9 @@ public function count(callable $predicate = null): Observable * exposing the sequence resulting from the selector function's invocation. For specializations with fixed subject * types, see Publish, PublishLast, and Replay. * - * @param \Rx\Subject\Subject $subject + * @param Subject $subject * @param callable|null $selector - * @return Observable + * @return ($selector is null ? ConnectableObservable : MulticastObservable) * * @demo multicast/multicast.php * @operator @@ -1247,13 +1261,13 @@ public function multicast(Subject $subject, callable $selector = null): Observab * For specializations with fixed subject types, see Publish, PublishLast, and Replay. * * @param callable $subjectSelector - * @param callable|null $selector - * @return \Rx\Observable\ConnectableObservable|\Rx\Observable\MulticastObservable + * @param callable $selector + * @return MulticastObservable * * @operator * @reactivex publish */ - public function multicastWithSelector(callable $subjectSelector, callable $selector = null): MulticastObservable + public function multicastWithSelector(callable $subjectSelector, callable $selector): MulticastObservable { return new MulticastObservable($this, $subjectSelector, $selector); } @@ -1264,15 +1278,19 @@ public function multicastWithSelector(callable $subjectSelector, callable $selec * This operator is a specialization of Multicast using a regular Subject. * * @param callable|null $selector - * @return \Rx\Observable\ConnectableObservable|\Rx\Observable\MulticastObservable + * @return ($selector is null ? ConnectableObservable : MulticastObservable) * * @demo publish/publish.php * @operator * @reactivex publish */ - public function publish(callable $selector = null): Observable + public function publish(callable $selector = null): ObservableInterface { - return $this->multicast(new Subject(), $selector); + /** + * @var Subject $subject + */ + $subject = new Subject(); + return $this->multicast($subject, $selector); } /** @@ -1281,7 +1299,7 @@ public function publish(callable $selector = null): Observable * This operator is a specialization of Multicast using a AsyncSubject. * * @param callable|null $selector - * @return \Rx\Observable\ConnectableObservable|\Rx\Observable\MulticastObservable + * @return Observable * * @demo publish/publishLast.php * @operator @@ -1289,7 +1307,11 @@ public function publish(callable $selector = null): Observable */ public function publishLast(callable $selector = null): Observable { - return $this->multicast(new AsyncSubject(), $selector); + /** + * @var Subject $subject + */ + $subject = new AsyncSubject(); + return $this->multicast($subject, $selector); } /** @@ -1297,9 +1319,9 @@ public function publishLast(callable $selector = null): Observable * that shares a single subscription to the underlying sequence and starts with initialValue. * This operator is a specialization of Multicast using a BehaviorSubject. * - * @param mixed $initialValue + * @param T $initialValue * @param callable $selector - * @return \Rx\Observable\ConnectableObservable|\Rx\Observable\MulticastObservable + * @return ($selector is null ? ConnectableObservable : MulticastObservable) * * @demo publish/publishValue.php * @operator @@ -1307,7 +1329,11 @@ public function publishLast(callable $selector = null): Observable */ public function publishValue($initialValue, callable $selector = null): Observable { - return $this->multicast(new BehaviorSubject($initialValue), $selector); + /** + * @var Subject $subject + */ + $subject = new BehaviorSubject($initialValue); + return $this->multicast($subject, $selector); } /** @@ -1317,7 +1343,7 @@ public function publishValue($initialValue, callable $selector = null): Observab * from zero to one, then shares that subscription with all subsequent observers until the number of observers * returns to zero, at which point the subscription is disposed. * - * @return \Rx\Observable\RefCountObservable An observable sequence that contains the elements of a sequence + * @return RefCountObservable An observable sequence that contains the elements of a sequence * produced by multicasting the source sequence. * * @demo share/share.php @@ -1335,7 +1361,7 @@ public function share(): RefCountObservable * * This operator behaves like share() in RxJS 5 * - * @return \Rx\Observable An observable sequence that contains the elements of a sequence + * @return Observable An observable sequence that contains the elements of a sequence * produced by multicasting the source sequence. * * @demo share/singleInstance.php @@ -1358,6 +1384,8 @@ public function singleInstance(): Observable ->publish() ->refCount(); } + + assert($observable instanceof Observable); return $observable; }; @@ -1374,8 +1402,8 @@ public function singleInstance(): Observable * from zero to one, then shares that subscription with all subsequent observers until the number of observers * returns to zero, at which point the subscription is disposed. * - * @param $initialValue - * @return \Rx\Observable\RefCountObservable + * @param mixed $initialValue + * @return RefCountObservable * * @demo share/shareValue.php * @operator @@ -1397,7 +1425,7 @@ public function shareValue($initialValue): RefCountObservable * @param integer|null $bufferSize * @param integer|null $windowSize * @param \Rx\SchedulerInterface|null $scheduler - * @return \Rx\Observable\ConnectableObservable|\Rx\Observable\MulticastObservable + * @return ($selector is null ? ConnectableObservable : MulticastObservable) * * @demo replay/replay.php * @operator @@ -1418,8 +1446,8 @@ public function replay(callable $selector = null, int $bufferSize = null, int $w * * @param integer $bufferSize * @param integer $windowSize - * @param $scheduler - * @return \Rx\Observable\RefCountObservable + * @param SchedulerInterface $scheduler + * @return RefCountObservable * * @demo share/shareReplay.php * @operator @@ -1436,9 +1464,9 @@ public function shareReplay(int $bufferSize, int $windowSize = null, SchedulerIn * result selector function is omitted, a list with the elements of the observable sequences at corresponding * indexes will be yielded. * - * @param array $observables + * @param array> $observables * @param callable $selector - * @return Observable + * @return Observable * * @demo zip/zip.php * @demo zip/zip-result-selector.php @@ -1455,9 +1483,9 @@ public function zip(array $observables, callable $selector = null): Observable /** * Runs all observable sequences in parallel and collect their last elements. * - * @param array $observables + * @param array> $observables * @param callable|null $resultSelector - * @return ForkJoinObservable + * @return ForkJoinObservable * * @demo forkJoin/forkJoin.php * @operator @@ -1474,7 +1502,7 @@ public static function forkJoin(array $observables = [], callable $resultSelecto * retry once, then you must use ->retry(2). * * @param int $retryCount - * @return Observable + * @return Observable * * @demo retry/retry.php * @operator @@ -1492,7 +1520,7 @@ public function retry(int $retryCount = -1): Observable * errors and the notifier completes, it will complete the source sequence. * * @param callable $notifier - * @return Observable + * @return Observable * * @demo retry/retryWhen.php * @operator @@ -1510,9 +1538,9 @@ public function retryWhen(callable $notifier): Observable * any of the observable sequences produces an element. Observables need to be an array. * If the result selector is omitted, a list with the elements will be yielded. * - * @param array $observables + * @param array> $observables * @param callable|null $selector - * @return Observable + * @return Observable * * @demo combineLatest/combineLatest.php * @operator @@ -1528,9 +1556,9 @@ public function combineLatest(array $observables, callable $selector = null): Ob /** * Merges the specified observable sequences into one observable sequence by using the selector function only when the (first) source observable sequence produces an element. * - * @param array $observables + * @param array> $observables * @param callable|null $selector - * @return Observable - An observable sequence containing the result of combining elements of the sources using the specified result selector function. + * @return Observable - An observable sequence containing the result of combining elements of the sources using the specified result selector function. * * @demo withLatestFrom/withLatestFrom.php * @operator @@ -1546,8 +1574,8 @@ public function withLatestFrom(array $observables, callable $selector = null): O /** * Returns the specified value of an observable if the sequence is empty. * - * @param ObservableInterface $observable - * @return Observable + * @param ObservableInterface $observable + * @return Observable * * @demo defaultIfEmpty/defaultIfEmpty.php * @operator @@ -1564,7 +1592,7 @@ public function defaultIfEmpty(ObservableInterface $observable): Observable * Generates an observable sequence that repeats the given element the specified number of times. * * @param int $count - * @return Observable|EmptyObservable + * @return Observable|EmptyObservable * * @demo repeat/repeat.php * @operator @@ -1589,7 +1617,7 @@ public function repeat(int $count = -1): Observable * resubscribe to the source observable. * * @param callable $notifier - * @return Observable + * @return Observable * * @demo repeat/repeatWhen.php * @operator @@ -1606,7 +1634,7 @@ public function repeatWhen(callable $notifier): Observable * Wraps the source sequence in order to run its subscription and unsubscription logic on the specified scheduler. * * @param SchedulerInterface $scheduler - * @return Observable + * @return Observable */ public function subscribeOn(SchedulerInterface $scheduler): Observable { @@ -1618,9 +1646,9 @@ public function subscribeOn(SchedulerInterface $scheduler): Observable /** * Time shifts the observable sequence by dueTime. The relative time intervals between the values are preserved. * - * @param $delay + * @param int $delay * @param AsyncSchedulerInterface|null $scheduler - * @return Observable + * @return Observable * * @demo delay/delay.php * @operator @@ -1637,10 +1665,10 @@ public function delay(int $delay, AsyncSchedulerInterface $scheduler = null): Ob * Errors the observable sequence if no item is emitted in the specified time. * When a timeout occurs, this operator errors with an instance of Rx\Exception\TimeoutException * - * @param $timeout - * @param ObservableInterface $timeoutObservable + * @param int $timeout + * @param ?ObservableInterface $timeoutObservable * @param AsyncSchedulerInterface $scheduler - * @return Observable + * @return Observable * * @demo timeout/timeout.php * @operator @@ -1659,7 +1687,7 @@ public function timeout(int $timeout, ObservableInterface $timeoutObservable = n * * @param $count * @param int $skip - * @return Observable + * @return Observable * @throws \InvalidArgumentException * * @demo bufferWithCount/bufferWithCount.php @@ -1678,7 +1706,7 @@ public function bufferWithCount(int $count, int $skip = null): Observable * Continues an observable sequence that is terminated by an exception with the next observable sequence. * * @param callable $selector - * @return Observable + * @return Observable * * @demo catch/catch.php * @operator @@ -1696,7 +1724,7 @@ public function catch (callable $selector): Observable * Alias for catch * * @param callable $selector - * @return Observable + * @return Observable */ public function catchError(callable $selector): Observable { @@ -1708,7 +1736,7 @@ public function catchError(callable $selector): Observable * * @param mixed $startValue * @param SchedulerInterface $scheduler - * @return Observable + * @return Observable * * @demo startWith/startWith.php * @operator @@ -1722,9 +1750,9 @@ public function startWith($startValue, SchedulerInterface $scheduler = null): Ob /** * Prepends a sequence of values to an observable sequence with an argument of an array of values to prepend. * - * @param array $startArray + * @param array $startArray * @param SchedulerInterface $scheduler - * @return Observable + * @return Observable * * @demo startWith/startWithArray.php * @operator @@ -1741,7 +1769,7 @@ public function startWithArray(array $startArray, SchedulerInterface $scheduler * Returns the minimum value in an observable sequence according to the specified comparer. * * @param callable $comparer - * @return Observable + * @return Observable * * @demo min/min.php * @demo min/min-with-comparer.php @@ -1759,7 +1787,7 @@ public function min(callable $comparer = null): Observable * Returns the maximum value in an observable sequence according to the specified comparer. * * @param callable $comparer - * @return Observable + * @return Observable * * @demo max/max.php * @demo max/max-with-comparer.php @@ -1776,7 +1804,7 @@ public function max(callable $comparer = null): Observable /** * Materializes the implicit notifications of an observable sequence as explicit notifications. * - * @return Observable + * @return Observable * * @operator * @reactivex materialize-dematerialize @@ -1791,7 +1819,7 @@ public function materialize(): Observable /** * Dematerializes the explicit notification values of an observable sequence as implicit notifications. * - * @return Observable + * @return Observable * * @operator * @reactivex materialize-dematerialize @@ -1807,7 +1835,7 @@ public function dematerialize(): Observable * Records the timestamp for each value in an observable sequence. * * @param SchedulerInterface|null $scheduler - * @return Observable + * @return Observable * * @demo timestamp/timestamp.php * @operator @@ -1824,7 +1852,7 @@ public function timestamp(SchedulerInterface $scheduler = null): Observable * Transforms an observable sequence of observable sequences into an observable sequence producing values only * from the most recent observable sequence. * - * @return Observable - The observable sequence that at any point in time produces the elements of the most + * @return Observable - The observable sequence that at any point in time produces the elements of the most * recent inner observable sequence that has been received. * * @demo switch/switch.php @@ -1842,7 +1870,7 @@ public function switch (): Observable * @deprecated Use `switch` * Alias for switch * - * @return Observable + * @return Observable */ public function switchLatest(): Observable { @@ -1857,7 +1885,7 @@ public function switchLatest(): Observable * This operator is similar to concatAll() except that it will not hold onto Observables that come in before the * current one is finished completed. * - * @return Observable - An Observable sequence that is the result of concatenating non-overlapping items + * @return Observable - An Observable sequence that is the result of concatenating non-overlapping items * emitted by an Observable of Observables. * * @demo switch/switchFirst.php @@ -1880,7 +1908,7 @@ public function switchFirst(): Observable * when the source completes. * * @param callable $predicate - * @return Observable[] + * @return array> * * @demo partition/partition.php * @operator @@ -1899,9 +1927,9 @@ public function partition(callable $predicate): array /** * Propagates the observable sequence that reacts first. Also known as 'amb'. * - * @param Observable[] $observables + * @param array> $observables * @param SchedulerInterface $scheduler - * @return Observable + * @return Observable * * @demo race/race.php * @operator @@ -1913,6 +1941,7 @@ public static function race(array $observables, SchedulerInterface $scheduler = return $observables[0]; } + /** @phpstan-ignore-next-line */ return static::fromArray($observables, $scheduler)->lift(function () { return new RaceOperator(); }); @@ -1921,7 +1950,7 @@ public static function race(array $observables, SchedulerInterface $scheduler = /** * Computes the sum of a sequence of values * - * @return Observable + * @return Observable * * @demo sum/sum.php * @operator @@ -1938,7 +1967,7 @@ public function sum(): Observable /** * Computes the average of an observable sequence of values. * - * @return Observable + * @return Observable * * @demo average/average.php * @operator @@ -1964,7 +1993,7 @@ public function average(): Observable * all elements in the Observable sequence. If a property can't be resolved the observable will error. * * @param mixed $property - * @return Observable + * @return Observable * * @demo pluck/pluck.php * @operator @@ -1974,6 +2003,7 @@ public function pluck($property): Observable { $args = func_get_args(); if (count($args) > 1) { + /** @phpstan-ignore-next-line */ return call_user_func_array([$this->pluck(array_shift($args)), 'pluck'], $args); } @@ -1998,7 +2028,7 @@ public function pluck($property): Observable * * @param $throttleDuration * @param SchedulerInterface $scheduler - * @return Observable + * @return Observable * * @demo throttle/throttle.php * @operator @@ -2014,7 +2044,7 @@ public function throttle(int $throttleDuration, SchedulerInterface $scheduler = /** * If the source Observable is empty it returns an Observable that emits true, otherwise it emits false. * - * @return Observable + * @return Observable * * @demo isEmpty/isEmpty.php * @demo isEmpty/isEmpty-false.php @@ -2032,7 +2062,7 @@ public function isEmpty(): Observable * Will call a specified function when the source terminates on complete or error. * * @param callable $callback - * @return Observable + * @return Observable * * @demo finally/finally.php * @demo finally/finally-error.php @@ -2049,8 +2079,9 @@ public function finally(callable $callback): Observable /** * Converts a promise into an observable * - * @param PromiseInterface $promise - * @return Observable + * @template X + * @param PromiseInterface $promise + * @return Observable * @throws \InvalidArgumentException * * @demo promise/fromPromise.php @@ -2065,8 +2096,8 @@ public static function fromPromise(PromiseInterface $promise): Observable /** * Converts Observable into a Promise * - * @param Deferred $deferred - * @return PromiseInterface + * @param ?Deferred $deferred + * @return PromiseInterface * @throws \InvalidArgumentException */ public function toPromise(Deferred $deferred = null): PromiseInterface @@ -2078,7 +2109,7 @@ public function toPromise(Deferred $deferred = null): PromiseInterface * Will apply given function to the source observable. * * @param callable $compose function that applies operators to source observable. Must return observable. - * @return Observable + * @return Observable * * @demo compose/compose.php */ diff --git a/src/Observable/AnonymousObservable.php b/src/Observable/AnonymousObservable.php index edcfd693..24363bd7 100644 --- a/src/Observable/AnonymousObservable.php +++ b/src/Observable/AnonymousObservable.php @@ -7,11 +7,19 @@ use Rx\Disposable\CallbackDisposable; use Rx\DisposableInterface; use Rx\Observable; +use Rx\ObservableInterface; use Rx\ObserverInterface; use Rx\Observer\AutoDetachObserver; +/** + * @template T + * @template-extends Observable + */ class AnonymousObservable extends Observable { + /** + * @var callable + */ private $subscribeAction; public function __construct(callable $subscribeAction) diff --git a/src/Observable/ArrayObservable.php b/src/Observable/ArrayObservable.php index 7b1be03e..a868c307 100644 --- a/src/Observable/ArrayObservable.php +++ b/src/Observable/ArrayObservable.php @@ -6,15 +6,29 @@ use Rx\DisposableInterface; use Rx\Observable; +use Rx\ObservableInterface; use Rx\ObserverInterface; use Rx\SchedulerInterface; +/** + * @template T + * @template-extends Observable + */ class ArrayObservable extends Observable { + /** + * @var array + */ private $data; + /** + * @var SchedulerInterface + */ private $scheduler; + /** + * @param array $data + */ public function __construct(array $data, SchedulerInterface $scheduler) { $this->data = $data; @@ -32,6 +46,11 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface if ($count < $max) { $observer->onNext($values[$keys[$count]]); $count++; + /** + * @phpstan-ignore-next-line + * + * Ignores the following error: Comparison operation ">=" between int<1, max> and 1 is always true. + */ if ($count >= 1) { $reschedule(); return; diff --git a/src/Observable/ConnectableObservable.php b/src/Observable/ConnectableObservable.php index 377fc32f..f7e53abd 100644 --- a/src/Observable/ConnectableObservable.php +++ b/src/Observable/ConnectableObservable.php @@ -12,18 +12,20 @@ use Rx\Subject\Subject; /** + * @template T + * @template-extends Observable * Class ConnectableObservable * @package Rx\Observable */ class ConnectableObservable extends Observable { - /** @var \Rx\Subject\Subject */ + /** @var \Rx\Subject\Subject */ protected $subject; /** @var BinaryDisposable */ protected $subscription; - /** @var Observable */ + /** @var Observable */ protected $sourceObservable; /** @var bool */ @@ -31,8 +33,8 @@ class ConnectableObservable extends Observable /** * ConnectableObservable constructor. - * @param Observable $source - * @param \Rx\Subject\Subject $subject + * @param Observable $source + * @param \Rx\Subject\Subject $subject */ public function __construct(Observable $source, Subject $subject = null) { @@ -63,6 +65,9 @@ public function connect(): DisposableInterface return $this->subscription; } + /** + * @return RefCountObservable + */ public function refCount(): RefCountObservable { return new RefCountObservable($this); diff --git a/src/Observable/EmptyObservable.php b/src/Observable/EmptyObservable.php index 57b4b3b6..b15cd772 100644 --- a/src/Observable/EmptyObservable.php +++ b/src/Observable/EmptyObservable.php @@ -9,8 +9,15 @@ use Rx\ObserverInterface; use Rx\SchedulerInterface; +/** + * @template T + * @template-extends Observable + */ class EmptyObservable extends Observable { + /** + * @var SchedulerInterface + */ private $scheduler; public function __construct(SchedulerInterface $scheduler) diff --git a/src/Observable/ErrorObservable.php b/src/Observable/ErrorObservable.php index 53a95d58..b962dc46 100644 --- a/src/Observable/ErrorObservable.php +++ b/src/Observable/ErrorObservable.php @@ -9,9 +9,20 @@ use Rx\ObserverInterface; use Rx\SchedulerInterface; +/** + * @template T + * @template-extends Observable + */ class ErrorObservable extends Observable { + /** + * @var \Throwable + */ private $error; + + /** + * @var SchedulerInterface + */ private $scheduler; public function __construct(\Throwable $error, SchedulerInterface $scheduler) diff --git a/src/Observable/ForkJoinObservable.php b/src/Observable/ForkJoinObservable.php index d7f35221..ef9fe83f 100644 --- a/src/Observable/ForkJoinObservable.php +++ b/src/Observable/ForkJoinObservable.php @@ -10,19 +10,35 @@ use Rx\ObserverInterface; use Rx\Disposable\CompositeDisposable; +/** + * @template T + * @template-extends Observable + */ class ForkJoinObservable extends Observable { /** - * @var Observable[] + * @var array> */ private $observables; + /** + * @var array + */ private $values = []; + /** + * @var int + */ private $completed = 0; + /** + * @var callable|null + */ private $resultSelector; + /** + * @param array> $observables + */ public function __construct(array $observables = [], callable $resultSelector = null) { $this->observables = $observables; diff --git a/src/Observable/GroupedObservable.php b/src/Observable/GroupedObservable.php index 36ba1d33..656e4eb9 100644 --- a/src/Observable/GroupedObservable.php +++ b/src/Observable/GroupedObservable.php @@ -11,11 +11,26 @@ use Rx\Disposable\RefCountDisposable; use Rx\DisposableInterface; +/** + * @template T + * @template-extends Observable + */ class GroupedObservable extends Observable { + /** + * @var mixed + */ private $key; + + /** + * @var ObservableInterface + */ private $underlyingObservable; + /** + * @param mixed $key + * @param ObservableInterface $underlyingObservable + */ public function __construct($key, ObservableInterface $underlyingObservable, RefCountDisposable $mergedDisposable = null) { $this->key = $key; @@ -25,6 +40,9 @@ public function __construct($key, ObservableInterface $underlyingObservable, Ref $this->newUnderlyingObservable($mergedDisposable, $underlyingObservable); } + /** + * @return mixed + */ public function getKey() { return $this->key; @@ -35,6 +53,10 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface return $this->underlyingObservable->subscribe($observer); } + /** + * @param ObservableInterface $underlyingObservable + * @return Observable + */ private function newUnderlyingObservable(RefCountDisposable $mergedDisposable, ObservableInterface $underlyingObservable): Observable { return new AnonymousObservable( diff --git a/src/Observable/IntervalObservable.php b/src/Observable/IntervalObservable.php index 90845c1e..92cbd3cb 100644 --- a/src/Observable/IntervalObservable.php +++ b/src/Observable/IntervalObservable.php @@ -9,8 +9,15 @@ use Rx\ObserverInterface; use Rx\AsyncSchedulerInterface; +/** + * @template T + * @template-extends Observable + */ class IntervalObservable extends Observable { + /** + * @var int + */ private $interval; /** @var AsyncSchedulerInterface */ diff --git a/src/Observable/IteratorObservable.php b/src/Observable/IteratorObservable.php index 3bfb3958..ddcef1a1 100644 --- a/src/Observable/IteratorObservable.php +++ b/src/Observable/IteratorObservable.php @@ -9,13 +9,23 @@ use Rx\ObserverInterface; use Rx\SchedulerInterface; +/** + * @template T + * @template-extends Observable + */ class IteratorObservable extends Observable { + /** + * @var \Iterator + */ private $items; + /** + * @var SchedulerInterface + */ private $scheduler; - public function __construct(\Iterator $items, SchedulerInterface $scheduler = null) + public function __construct(\Iterator $items, SchedulerInterface $scheduler) { $this->items = $items; $this->scheduler = $scheduler; diff --git a/src/Observable/MulticastObservable.php b/src/Observable/MulticastObservable.php index 027340ab..65db6217 100644 --- a/src/Observable/MulticastObservable.php +++ b/src/Observable/MulticastObservable.php @@ -10,25 +10,27 @@ use Rx\ObserverInterface; /** + * @template T + * @template-extends Observable * Class MulticastObservable * @package Rx\Observable */ class MulticastObservable extends Observable { - /** @var \Rx\Observable */ + /** @var \Rx\Observable */ private $source; - /** @var callable */ + /** @var callable */ private $fn1; - /** @var callable */ + /** @var callable */ private $fn2; /** * MulticastObservable constructor. - * @param $source - * @param $fn1 - * @param $fn2 + * @param Observable $source + * @param callable $fn1 + * @param callable $fn2 */ public function __construct(Observable $source, callable $fn1, callable $fn2) { diff --git a/src/Observable/NeverObservable.php b/src/Observable/NeverObservable.php index 34925faa..8588437f 100644 --- a/src/Observable/NeverObservable.php +++ b/src/Observable/NeverObservable.php @@ -9,6 +9,10 @@ use Rx\Observable; use Rx\ObserverInterface; +/** + * @template T + * @template-extends Observable + */ class NeverObservable extends Observable { protected function _subscribe(ObserverInterface $observer): DisposableInterface diff --git a/src/Observable/RangeObservable.php b/src/Observable/RangeObservable.php index 785033a0..73c7fffa 100644 --- a/src/Observable/RangeObservable.php +++ b/src/Observable/RangeObservable.php @@ -9,12 +9,25 @@ use Rx\ObserverInterface; use Rx\SchedulerInterface; +/** + * @template T + * @template-extends Observable + */ class RangeObservable extends Observable { + /** + * @var int + */ private $start; + /** + * @var int + */ private $count; + /** + * @var SchedulerInterface + */ private $scheduler; public function __construct(int $start, int $count, SchedulerInterface $scheduler) diff --git a/src/Observable/RefCountObservable.php b/src/Observable/RefCountObservable.php index 970d055d..fb65fe4f 100644 --- a/src/Observable/RefCountObservable.php +++ b/src/Observable/RefCountObservable.php @@ -11,20 +11,26 @@ use Rx\ObserverInterface; /** + * @template T + * @template-extends Observable + * * Class RefCountObservable * @package Rx\Observable */ class RefCountObservable extends Observable { - /** @var \Rx\Observable\ConnectableObservable */ + /** @var \Rx\Observable\ConnectableObservable */ protected $source; /** @var int */ protected $count; - /** @var BinaryDisposable */ + /** @var DisposableInterface */ protected $connectableSubscription; + /** + * @param ConnectableObservable $source + */ public function __construct(ConnectableObservable $source) { $this->source = $source; diff --git a/src/Observable/ReturnObservable.php b/src/Observable/ReturnObservable.php index c777e148..2fe50b61 100644 --- a/src/Observable/ReturnObservable.php +++ b/src/Observable/ReturnObservable.php @@ -7,14 +7,29 @@ use Rx\Disposable\CompositeDisposable; use Rx\DisposableInterface; use Rx\Observable; +use Rx\ObservableInterface; use Rx\ObserverInterface; use Rx\SchedulerInterface; +/** + * @template T + * @template-extends Observable + */ class ReturnObservable extends Observable { + /** + * @var T + */ private $value; + + /** + * @var SchedulerInterface + */ private $scheduler; + /** + * @param T $value + */ public function __construct($value, SchedulerInterface $scheduler) { $this->value = $value; diff --git a/src/Observable/TimerObservable.php b/src/Observable/TimerObservable.php index 1402b7a0..65bff764 100644 --- a/src/Observable/TimerObservable.php +++ b/src/Observable/TimerObservable.php @@ -9,10 +9,20 @@ use Rx\ObserverInterface; use Rx\AsyncSchedulerInterface; +/** + * @template T + * @template-extends Observable + */ class TimerObservable extends Observable { + /** + * @var int + */ private $dueTime; + /** + * @var AsyncSchedulerInterface + */ private $scheduler; public function __construct(int $dueTime, AsyncSchedulerInterface $scheduler) diff --git a/src/ObservableFactoryWrapper.php b/src/ObservableFactoryWrapper.php index d25839cc..72d70e0f 100644 --- a/src/ObservableFactoryWrapper.php +++ b/src/ObservableFactoryWrapper.php @@ -7,15 +7,28 @@ use React\Promise\PromiseInterface; use Rx\React\Promise; +/** + * @template T + */ final class ObservableFactoryWrapper { + /** + * @var (callable(): (PromiseInterface|ObservableInterface)) + */ private $selector; + /** + * @param (callable(): (PromiseInterface|ObservableInterface)) $selector + */ public function __construct(callable $selector) { $this->selector = $selector; } + /** + * @return Observable + * @throws \ReflectionException + */ public function __invoke(): Observable { $result = call_user_func_array($this->selector, func_get_args()); @@ -24,7 +37,8 @@ public function __invoke(): Observable $result = Promise::toObservable($result); } - if (!$result instanceof ObservableInterface) { + if (!$result instanceof Observable) { + /** @phpstan-ignore-next-line */ $reflectCallable = new \ReflectionFunction($this->selector); throw new \Exception("You must return an Observable or Promise in {$reflectCallable->getFileName()} on line {$reflectCallable->getStartLine()}\n"); } diff --git a/src/ObservableInterface.php b/src/ObservableInterface.php index 754118f6..07357bd2 100644 --- a/src/ObservableInterface.php +++ b/src/ObservableInterface.php @@ -4,10 +4,13 @@ namespace Rx; +/** + * @template-covariant T + */ interface ObservableInterface { /** - * @param callable|ObserverInterface|null $onNextOrObserver + * @param (callable(T): void)|ObserverInterface|null $onNextOrObserver * @param callable|null $onError * @param callable|null $onCompleted * @return DisposableInterface diff --git a/src/Observer/AbstractObserver.php b/src/Observer/AbstractObserver.php index 016b866d..3272fb61 100644 --- a/src/Observer/AbstractObserver.php +++ b/src/Observer/AbstractObserver.php @@ -8,6 +8,9 @@ abstract class AbstractObserver implements ObserverInterface { + /** + * @var bool + */ private $isStopped = false; public function onCompleted() @@ -39,9 +42,20 @@ public function onNext($value) $this->next($value); } + /** + * @return void + */ abstract protected function completed(); + /** + * @template T + * @param T $value + * @return void + */ abstract protected function next($value); + /** + * @return void + */ abstract protected function error(\Throwable $error); } diff --git a/src/Observer/AutoDetachObserver.php b/src/Observer/AutoDetachObserver.php index fd6a31c1..3dc9730b 100644 --- a/src/Observer/AutoDetachObserver.php +++ b/src/Observer/AutoDetachObserver.php @@ -11,8 +11,14 @@ class AutoDetachObserver extends AbstractObserver { + /** + * @var ObserverInterface + */ private $observer; + /** + * @var SingleAssignmentDisposable + */ private $disposable; public function __construct(ObserverInterface $observer) @@ -21,6 +27,9 @@ public function __construct(ObserverInterface $observer) $this->disposable = new SingleAssignmentDisposable(); } + /** + * @return void + */ public function setDisposable(DisposableInterface $disposable = null) { $disposable = $disposable ?: new EmptyDisposable(); @@ -50,6 +59,11 @@ protected function error(\Throwable $exception) } } + /** + * @template T + * @param T $value + * @return void + */ protected function next($value) { try { @@ -60,6 +74,9 @@ protected function next($value) } } + /** + * @return void + */ public function dispose() { $this->disposable->dispose(); diff --git a/src/Observer/CallbackObserver.php b/src/Observer/CallbackObserver.php index 2234c028..bec5b71e 100644 --- a/src/Observer/CallbackObserver.php +++ b/src/Observer/CallbackObserver.php @@ -6,13 +6,16 @@ class CallbackObserver extends AbstractObserver { - /** @var callable|null */ + /** + * @template T + * @var callable(T) + */ private $onNext; - /** @var callable|null */ + /** @var callable */ private $onError; - /** @var callable|null */ + /** @var callable */ private $onCompleted; public function __construct(callable $onNext = null, callable $onError = null, callable $onCompleted = null) @@ -40,12 +43,17 @@ protected function error(\Throwable $error) ($this->onError)($error); } + /** + * @template T + * @param T $value + * @return void + */ protected function next($value) { ($this->onNext)($value); } - private function getOrDefault(callable $callback = null, $default = null): callable + private function getOrDefault(callable $callback = null, callable $default): callable { if (null === $callback) { return $default; diff --git a/src/Observer/DoObserver.php b/src/Observer/DoObserver.php index 04bfc094..84ffbbeb 100644 --- a/src/Observer/DoObserver.php +++ b/src/Observer/DoObserver.php @@ -8,13 +8,16 @@ class DoObserver implements ObserverInterface { - /** @var callable|null */ + /** + * @template T + * @var callable(T) + */ private $onNext; - /** @var callable|null */ + /** @var callable */ private $onError; - /** @var callable|null */ + /** @var callable */ private $onCompleted; public function __construct(callable $onNext = null, callable $onError = null, callable $onCompleted = null) @@ -41,12 +44,17 @@ public function onError(\Throwable $error) ($this->onError)($error); } + /** + * @template T + * @param T $value + * @return void + */ public function onNext($value) { ($this->onNext)($value); } - private function getOrDefault(callable $callback = null, $default = null): callable + private function getOrDefault(callable $callback = null, callable $default): callable { if (null === $callback) { return $default; diff --git a/src/Observer/ScheduledObserver.php b/src/Observer/ScheduledObserver.php index a3dc7de2..bc879ca6 100644 --- a/src/Observer/ScheduledObserver.php +++ b/src/Observer/ScheduledObserver.php @@ -48,6 +48,11 @@ protected function completed() }; } + /** + * @template T + * @param T $value + * @return void + */ protected function next($value) { $this->queue[] = function () use ($value) { @@ -62,6 +67,9 @@ protected function error(\Throwable $error) }; } + /** + * @return void + */ public function ensureActive() { $isOwner = false; @@ -99,6 +107,9 @@ function ($recurse) { ); } + /** + * @return void + */ public function dispose() { $this->disposable->dispose(); diff --git a/src/ObserverInterface.php b/src/ObserverInterface.php index 70b2e382..56b99a7d 100644 --- a/src/ObserverInterface.php +++ b/src/ObserverInterface.php @@ -6,9 +6,20 @@ interface ObserverInterface { + /** + * @return void + */ public function onCompleted(); + /** + * @return void + */ public function onError(\Throwable $error); + /** + * @template T + * @param T $value + * @return void + */ public function onNext($value); } diff --git a/src/Operator/BufferWithCountOperator.php b/src/Operator/BufferWithCountOperator.php index b41dd826..4662670d 100644 --- a/src/Operator/BufferWithCountOperator.php +++ b/src/Operator/BufferWithCountOperator.php @@ -14,7 +14,7 @@ final class BufferWithCountOperator implements OperatorInterface /** @var int */ private $count; - /** @var */ + /** @var ?int */ private $skip; /** @var int */ diff --git a/src/Operator/CatchErrorOperator.php b/src/Operator/CatchErrorOperator.php index 77d95a33..a80eb7ff 100644 --- a/src/Operator/CatchErrorOperator.php +++ b/src/Operator/CatchErrorOperator.php @@ -12,6 +12,9 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class CatchErrorOperator implements OperatorInterface { @@ -29,13 +32,13 @@ public function __invoke(ObservableInterface $observable, ObserverInterface $obs $disposable = new CompositeDisposable(); $onError = function (\Throwable $e) use (&$isDisposed, $observer, $observable, $disposable) { - + /** @phpstan-ignore-next-line */ if ($isDisposed) { return; } try { - /** @var Observable $result */ + /** @var Observable $result */ $result = ($this->errorSelector)($e, $observable); $subscription = $result->subscribe($observer); diff --git a/src/Operator/CombineLatestOperator.php b/src/Operator/CombineLatestOperator.php index a53dce7d..c5851239 100644 --- a/src/Operator/CombineLatestOperator.php +++ b/src/Operator/CombineLatestOperator.php @@ -10,14 +10,20 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class CombineLatestOperator implements OperatorInterface { - /** @var ObservableInterface[] */ + /** @var array> */ private $observables; /** @var callable */ private $resultSelector; + /** + * @param array> $observables + */ public function __construct(array $observables, callable $resultSelector = null) { if (null === $resultSelector) { @@ -53,7 +59,7 @@ public function __invoke(ObservableInterface $observable, ObserverInterface $obs $hasValue[$key] = false; $cbObserver = new CallbackObserver( - function ($value) use ($count, &$hasValue, $key, &$values, $observer, &$waitingForValues, &$waitingToComplete) { + function ($value) use (&$hasValue, $key, &$values, $observer, &$waitingForValues, &$waitingToComplete) { // If an observable has completed before it has emitted, we need to complete right away if ($waitingForValues > $waitingToComplete) { diff --git a/src/Operator/ConcatAllOperator.php b/src/Operator/ConcatAllOperator.php index f749a02f..c7c08138 100644 --- a/src/Operator/ConcatAllOperator.php +++ b/src/Operator/ConcatAllOperator.php @@ -12,15 +12,18 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class ConcatAllOperator implements OperatorInterface { - /** @var array */ + /** @var array> */ private $buffer; /** @var CompositeDisposable */ private $disposable; - /** @var SerialDisposable */ + /** @var DisposableInterface */ private $innerDisposable; /** @var bool */ @@ -45,7 +48,7 @@ public function __construct() public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface { $subscription = $observable->subscribe(new CallbackObserver( - function (ObservableInterface $innerObservable) use ($observable, $observer) { + function (ObservableInterface $innerObservable) use ($observer) { try { if ($this->startBuffering === true) { @@ -67,6 +70,7 @@ function (ObservableInterface $innerObservable) use ($observable, $observer) { } if ($obs) { + /** @phpstan-ignore-next-line */ $subscribeToInner($obs); } elseif ($this->sourceCompleted === true) { $observer->onCompleted(); diff --git a/src/Operator/ConcatMapOperator.php b/src/Operator/ConcatMapOperator.php index 208f4293..bd08e2b6 100644 --- a/src/Operator/ConcatMapOperator.php +++ b/src/Operator/ConcatMapOperator.php @@ -5,6 +5,7 @@ namespace Rx\Operator; use Rx\DisposableInterface; +use Rx\Observable; use Rx\ObservableInterface; use Rx\ObserverInterface; @@ -13,7 +14,7 @@ final class ConcatMapOperator implements OperatorInterface /** @var callable */ private $selector; - /** @var callable */ + /** @var ?callable */ private $resultSelector; public function __construct(callable $selector, callable $resultSelector = null) @@ -24,13 +25,14 @@ public function __construct(callable $selector, callable $resultSelector = null) public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface { + assert($observable instanceof Observable); return $observable->mapWithIndex(function (int $index, $value) use ($observable, $observer) { - try { $result = ($this->selector)($value, $index, $observable); if ($this->resultSelector) { return $result->mapWithIndex(function ($innerIndex, $innerValue) use ($value, $index) { + /** @phpstan-ignore-next-line */ return ($this->resultSelector)($value, $innerValue, $index, $innerIndex); }); } diff --git a/src/Operator/ConcatOperator.php b/src/Operator/ConcatOperator.php index 40e0834c..1d01c59f 100644 --- a/src/Operator/ConcatOperator.php +++ b/src/Operator/ConcatOperator.php @@ -10,14 +10,17 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class ConcatOperator implements OperatorInterface { - /** @var \Rx\ObservableInterface */ + /** @var \Rx\ObservableInterface */ private $subsequentObservable; /** * Concat constructor. - * @param ObservableInterface $subsequentObservable + * @param ObservableInterface $subsequentObservable */ public function __construct(ObservableInterface $subsequentObservable) { diff --git a/src/Operator/CountOperator.php b/src/Operator/CountOperator.php index 2f0a3eef..7a66bb3f 100644 --- a/src/Operator/CountOperator.php +++ b/src/Operator/CountOperator.php @@ -11,7 +11,14 @@ final class CountOperator implements OperatorInterface { + /** + * @var int + */ private $count = 0; + + /** + * @var callable|null + */ private $predicate; public function __construct(callable $predicate = null) diff --git a/src/Operator/DefaultIfEmptyOperator.php b/src/Operator/DefaultIfEmptyOperator.php index 01e61ffd..6e35e3d7 100644 --- a/src/Operator/DefaultIfEmptyOperator.php +++ b/src/Operator/DefaultIfEmptyOperator.php @@ -10,14 +10,20 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class DefaultIfEmptyOperator implements OperatorInterface { - /** @var ObservableInterface */ + /** @var ObservableInterface */ private $observable; /** @var bool */ private $passThrough = false; + /** + * @param ObservableInterface $observable + */ public function __construct(ObservableInterface $observable) { $this->observable = $observable; diff --git a/src/Operator/DeferOperator.php b/src/Operator/DeferOperator.php index 2459deea..e5e94220 100644 --- a/src/Operator/DeferOperator.php +++ b/src/Operator/DeferOperator.php @@ -9,10 +9,14 @@ use Rx\ObservableInterface; use Rx\ObserverInterface; +/** + * @template T + */ final class DeferOperator implements OperatorInterface { - - /* @var Callable */ + /** + * @var (callable(): Observable) + */ private $factory; public function __construct(callable $factory) diff --git a/src/Operator/DelayOperator.php b/src/Operator/DelayOperator.php index 6e486683..69382c4f 100644 --- a/src/Operator/DelayOperator.php +++ b/src/Operator/DelayOperator.php @@ -14,16 +14,19 @@ use Rx\AsyncSchedulerInterface; use Rx\Timestamped; +/** + * @template T + */ final class DelayOperator implements OperatorInterface { /** @var int */ private $delayTime; - /** @var \SplQueue */ + /** @var \SplQueue */ private $queue; - /** @var DisposableInterface */ - private $schedulerDisposable; + /** @var ?DisposableInterface */ + private $schedulerDisposable = null; /** @var AsyncSchedulerInterface */ private $scheduler; @@ -37,7 +40,7 @@ public function __construct(int $delayTime, AsyncSchedulerInterface $scheduler) public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface { - /** @var AnonymousObservable $observable */ + /** @var AnonymousObservable $observable */ $disp = $observable ->materialize() ->timestamp($this->scheduler) diff --git a/src/Operator/DistinctOperator.php b/src/Operator/DistinctOperator.php index 095c63f3..bba046f1 100644 --- a/src/Operator/DistinctOperator.php +++ b/src/Operator/DistinctOperator.php @@ -13,11 +13,10 @@ final class DistinctOperator implements OperatorInterface { - - /** @var callable */ + /** @var ?callable */ protected $keySelector; - /** @var callable */ + /** @var ?callable */ protected $comparer; public function __construct(callable $keySelector = null, callable $comparer = null) @@ -32,7 +31,6 @@ public function __invoke(ObservableInterface $observable, ObserverInterface $obs $callbackObserver = new CallbackObserver( function ($value) use ($observer, &$values) { - try { $key = $this->keySelector ? ($this->keySelector)($value) : $value; @@ -55,7 +53,7 @@ function ($value) use ($observer, &$values) { $observer->onNext($value); } catch (\Throwable $e) { - return $observer->onError($e); + $observer->onError($e); } }, [$observer, 'onError'], diff --git a/src/Operator/DistinctUntilChangedOperator.php b/src/Operator/DistinctUntilChangedOperator.php index 11a98ab5..f911f810 100644 --- a/src/Operator/DistinctUntilChangedOperator.php +++ b/src/Operator/DistinctUntilChangedOperator.php @@ -11,8 +11,14 @@ final class DistinctUntilChangedOperator implements OperatorInterface { + /** + * @var callable|null + */ protected $keySelector; + /** + * @var callable + */ protected $comparer; public function __construct(callable $keySelector = null, callable $comparer = null) @@ -35,7 +41,8 @@ function ($value) use ($observer, &$hasCurrentKey, &$currentKey) { try { $key = ($this->keySelector)($value); } catch (\Throwable $e) { - return $observer->onError($e); + $observer->onError($e); + return; } } @@ -44,7 +51,8 @@ function ($value) use ($observer, &$hasCurrentKey, &$currentKey) { try { $comparerEquals = ($this->comparer)($currentKey, $key); } catch (\Throwable $e) { - return $observer->onError($e); + $observer->onError($e); + return; } } diff --git a/src/Operator/DoOnEachOperator.php b/src/Operator/DoOnEachOperator.php index 4358757d..9b80fd91 100644 --- a/src/Operator/DoOnEachOperator.php +++ b/src/Operator/DoOnEachOperator.php @@ -11,6 +11,9 @@ final class DoOnEachOperator implements OperatorInterface { + /** + * @var ObserverInterface + */ private $onEachObserver; public function __construct(ObserverInterface $observer) @@ -25,7 +28,8 @@ function ($x) use ($observer) { try { $this->onEachObserver->onNext($x); } catch (\Throwable $e) { - return $observer->onError($e); + $observer->onError($e); + return; } $observer->onNext($x); @@ -34,7 +38,8 @@ function ($err) use ($observer) { try { $this->onEachObserver->onError($err); } catch (\Throwable $e) { - return $observer->onError($e); + $observer->onError($e); + return; } $observer->onError($err); }, @@ -42,7 +47,8 @@ function () use ($observer) { try { $this->onEachObserver->onCompleted(); } catch (\Throwable $e) { - return $observer->onError($e); + $observer->onError($e); + return; } $observer->onCompleted(); } diff --git a/src/Operator/FilterOperator.php b/src/Operator/FilterOperator.php index a6e7bea7..50a579dc 100644 --- a/src/Operator/FilterOperator.php +++ b/src/Operator/FilterOperator.php @@ -11,6 +11,9 @@ final class FilterOperator implements OperatorInterface { + /** + * @var callable + */ private $predicate; public function __construct(callable $predicate) diff --git a/src/Operator/FinallyOperator.php b/src/Operator/FinallyOperator.php index e9ca6fd2..36b85ea2 100644 --- a/src/Operator/FinallyOperator.php +++ b/src/Operator/FinallyOperator.php @@ -8,6 +8,9 @@ use Rx\ObservableInterface; use Rx\ObserverInterface; +/** + * @template T + */ final class FinallyOperator implements OperatorInterface { /** @var callable */ @@ -22,7 +25,7 @@ public function __construct(callable $callback) } /** - * @param \Rx\ObservableInterface $observable + * @param \Rx\ObservableInterface $observable * @param \Rx\ObserverInterface $observer * @return \Rx\DisposableInterface */ diff --git a/src/Operator/GroupByUntilOperator.php b/src/Operator/GroupByUntilOperator.php index 62946d73..408c09cc 100644 --- a/src/Operator/GroupByUntilOperator.php +++ b/src/Operator/GroupByUntilOperator.php @@ -14,12 +14,34 @@ use Rx\ObserverInterface; use Rx\Subject\Subject; +/** + * @template T + */ final class GroupByUntilOperator implements OperatorInterface { + /** + * @var callable + */ private $keySelector; + + /** + * @var callable + */ private $elementSelector; + + /** + * @var callable + */ private $durationSelector; + + /** + * @var callable + */ private $keySerializer; + + /** + * @var array> + */ private $map = []; public function __construct(callable $keySelector, callable $elementSelector = null, callable $durationSelector = null, callable $keySerializer = null) @@ -58,6 +80,7 @@ public function __invoke(ObservableInterface $observable, ObserverInterface $obs foreach ($this->map as $w) { $w->onError($e); } + /** @phpstan-ignore-next-line */ if ($sourceEmits) { $observer->onError($e); } @@ -73,6 +96,7 @@ function ($element) use ($observer, $handleError, $refCountDisposable, $groupDis return; } + /** @phpstan-ignore-next-line */ if (!$sourceEmits && !isset($this->map[$serializedKey])) { return; } @@ -124,6 +148,7 @@ function () use ($observer, &$sourceEmits) { foreach ($this->map as $w) { $w->onCompleted(); } + /** @phpstan-ignore-next-line */ if ($sourceEmits) { $observer->onCompleted(); } diff --git a/src/Operator/MapOperator.php b/src/Operator/MapOperator.php index 38436d79..ff58bcfa 100644 --- a/src/Operator/MapOperator.php +++ b/src/Operator/MapOperator.php @@ -13,6 +13,9 @@ final class MapOperator implements OperatorInterface { + /** + * @var callable + */ private $selector; public function __construct(callable $selector) @@ -34,6 +37,7 @@ function ($nextValue) use ($observer, &$disposed) { } catch (\Throwable $e) { $observer->onError($e); } + /** @phpstan-ignore-next-line */ if (!$disposed) { $observer->onNext($value); } diff --git a/src/Operator/MaxOperator.php b/src/Operator/MaxOperator.php index d444dd5e..1fb5ec49 100644 --- a/src/Operator/MaxOperator.php +++ b/src/Operator/MaxOperator.php @@ -11,6 +11,9 @@ final class MaxOperator implements OperatorInterface { + /** + * @var callable + */ private $comparer; public function __construct(callable $comparer = null) diff --git a/src/Operator/MergeAllOperator.php b/src/Operator/MergeAllOperator.php index 5cd63403..13963a73 100644 --- a/src/Operator/MergeAllOperator.php +++ b/src/Operator/MergeAllOperator.php @@ -37,6 +37,7 @@ function ($error) use ($observer) { function () use (&$group, &$innerSubscription, &$isStopped, $observer) { $group->remove($innerSubscription); + /** @phpstan-ignore-next-line */ if ($isStopped && $group->count() === 1) { $observer->onCompleted(); } diff --git a/src/Operator/MinOperator.php b/src/Operator/MinOperator.php index 4bd85389..0135a937 100644 --- a/src/Operator/MinOperator.php +++ b/src/Operator/MinOperator.php @@ -11,6 +11,9 @@ final class MinOperator implements OperatorInterface { + /** + * @var callable + */ private $comparer; public function __construct(callable $comparer = null) diff --git a/src/Operator/OperatorInterface.php b/src/Operator/OperatorInterface.php index b8e2d700..5a196998 100644 --- a/src/Operator/OperatorInterface.php +++ b/src/Operator/OperatorInterface.php @@ -10,5 +10,9 @@ interface OperatorInterface { + /** + * @template T + * @param ObservableInterface $observable + */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface; } diff --git a/src/Operator/RaceOperator.php b/src/Operator/RaceOperator.php index b5438267..4b7bc985 100644 --- a/src/Operator/RaceOperator.php +++ b/src/Operator/RaceOperator.php @@ -12,13 +12,15 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class RaceOperator implements OperatorInterface { - /** @var bool */ private $hasFirst = false; - /** @var Observable[] */ + /** @var array> */ private $observables = []; /** @var DisposableInterface[] */ @@ -55,7 +57,7 @@ function () use ($observer) { $this->innerSubscription->add($subscription); } - $this->observables = null; + $this->observables = []; } ); @@ -65,6 +67,12 @@ function () use ($observer) { } + /** + * @param ObservableInterface $observable + * @param mixed $outerIndex + * + * @return DisposableInterface + */ private function subscribeToResult(ObservableInterface $observable, ObserverInterface $observer, $outerIndex) { return $observable->subscribe(new CallbackObserver( diff --git a/src/Operator/ReduceOperator.php b/src/Operator/ReduceOperator.php index 6ff158f9..8181c0ae 100644 --- a/src/Operator/ReduceOperator.php +++ b/src/Operator/ReduceOperator.php @@ -13,12 +13,20 @@ final class ReduceOperator implements OperatorInterface { /** @var callable */ protected $accumulator; + + /** + * @var mixed + */ protected $seed; + + /** + * @var bool + */ protected $hasSeed; /** * @param callable $accumulator - * @param $seed + * @param mixed $seed */ public function __construct(callable $accumulator, $seed) { @@ -51,7 +59,7 @@ function ($x) use ($observer, &$hasAccumulation, &$accumulation, &$hasValue) { function ($e) use ($observer) { $observer->onError($e); }, - function () use ($observer, &$hasAccumulation, &$accumulation, &$hasValue) { + function () use ($observer, &$accumulation, &$hasValue) { if ($hasValue) { $observer->onNext($accumulation); } else { diff --git a/src/Operator/RepeatOperator.php b/src/Operator/RepeatOperator.php index e11ccdae..f00695ed 100644 --- a/src/Operator/RepeatOperator.php +++ b/src/Operator/RepeatOperator.php @@ -13,6 +13,9 @@ final class RepeatOperator implements OperatorInterface { + /** + * @var int + */ private $repeatCount; public function __construct(int $repeatCount = -1) @@ -34,7 +37,7 @@ public function __invoke(ObservableInterface $observable, ObserverInterface $obs $disposable->setDisposable($observable->subscribe(new CallbackObserver( [$observer, 'onNext'], [$observer, 'onError'], - function () use (&$completeCount, $observable, $observer, &$disposable, &$subscribe) { + function () use (&$completeCount, $observer, &$subscribe) { $completeCount++; if ($this->repeatCount === -1 || $completeCount < $this->repeatCount) { $subscribe(); diff --git a/src/Operator/RepeatWhenOperator.php b/src/Operator/RepeatWhenOperator.php index ccc84cfe..024cf696 100644 --- a/src/Operator/RepeatWhenOperator.php +++ b/src/Operator/RepeatWhenOperator.php @@ -13,15 +13,18 @@ use Rx\ObserverInterface; use Rx\Subject\Subject; +/** + * @template T + */ final class RepeatWhenOperator implements OperatorInterface { /** @var callable */ private $notificationHandler; - /** @var Subject */ + /** @var Subject */ private $completions; - /** @var Subject */ + /** @var Subject */ private $notifier; /** @var CompositeDisposable */ @@ -52,12 +55,12 @@ public function __invoke(ObservableInterface $observable, ObserverInterface $obs $outerDisposable = new SerialDisposable(); $this->disposable->add($outerDisposable); - $subscribe = function () use ($outerDisposable, $observable, $observer, &$subscribe) { + $subscribe = function () use ($outerDisposable, $observable, $observer) { $this->sourceComplete = false; $outerSubscription = $observable->subscribe(new CallbackObserver( [$observer, 'onNext'], [$observer, 'onError'], - function () use ($observer, &$subscribe, $outerDisposable) { + function () use ($observer, $outerDisposable) { $this->sourceComplete = true; if (!$this->repeat) { $observer->onCompleted(); diff --git a/src/Operator/RetryOperator.php b/src/Operator/RetryOperator.php index b2eaf85b..1a611674 100644 --- a/src/Operator/RetryOperator.php +++ b/src/Operator/RetryOperator.php @@ -13,6 +13,9 @@ final class RetryOperator implements OperatorInterface { + /** + * @var int + */ private $retryCount; public function __construct(int $retryCount = -1) diff --git a/src/Operator/RetryWhenOperator.php b/src/Operator/RetryWhenOperator.php index 17a91350..262599a1 100644 --- a/src/Operator/RetryWhenOperator.php +++ b/src/Operator/RetryWhenOperator.php @@ -14,6 +14,9 @@ final class RetryWhenOperator implements OperatorInterface { + /** + * @var callable + */ private $notificationHandler; public function __construct(callable $notificationHandler) @@ -52,6 +55,7 @@ function ($err) use ( $disposable->remove($sourceDisposable); $sourceDisposable->dispose(); + /** @phpstan-ignore-next-line */ if ($innerCompleted) { $observer->onCompleted(); return; diff --git a/src/Operator/ScanOperator.php b/src/Operator/ScanOperator.php index 3b38a4b3..5963ff14 100644 --- a/src/Operator/ScanOperator.php +++ b/src/Operator/ScanOperator.php @@ -11,10 +11,20 @@ final class ScanOperator implements OperatorInterface { + /** + * @var callable + */ private $accumulator; + /** + * @var mixed|null + */ private $seed; + /** + * @param callable $accumulator + * @param mixed|null $seed + */ public function __construct(callable $accumulator, $seed = null) { $this->accumulator = $accumulator; @@ -54,7 +64,7 @@ function () use ($observer, &$hasValue, &$hasSeed) { return $observable->subscribe($cbObserver); } - private function tryCatch($functionToWrap) + private function tryCatch(callable $functionToWrap): callable { return function ($x, $y) use ($functionToWrap) { try { diff --git a/src/Operator/SkipLastOperator.php b/src/Operator/SkipLastOperator.php index 45f97c68..2e0e0943 100644 --- a/src/Operator/SkipLastOperator.php +++ b/src/Operator/SkipLastOperator.php @@ -9,11 +9,17 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class SkipLastOperator implements OperatorInterface { + /** + * @var int + */ private $count; - /** @var array */ + /** @var array */ private $q; public function __construct(int $count) diff --git a/src/Operator/SkipOperator.php b/src/Operator/SkipOperator.php index 56c6f6cf..849295e4 100644 --- a/src/Operator/SkipOperator.php +++ b/src/Operator/SkipOperator.php @@ -11,6 +11,9 @@ final class SkipOperator implements OperatorInterface { + /** + * @var int + */ private $count; public function __construct(int $count) diff --git a/src/Operator/SkipUntilOperator.php b/src/Operator/SkipUntilOperator.php index f38107d2..5c547589 100644 --- a/src/Operator/SkipUntilOperator.php +++ b/src/Operator/SkipUntilOperator.php @@ -11,10 +11,19 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class SkipUntilOperator implements OperatorInterface { + /** + * @var ObservableInterface + */ private $other; + /** + * @param ObservableInterface $other + */ public function __construct(ObservableInterface $other) { $this->other = $other; diff --git a/src/Operator/StartWithArrayOperator.php b/src/Operator/StartWithArrayOperator.php index 62441456..8de000e5 100644 --- a/src/Operator/StartWithArrayOperator.php +++ b/src/Operator/StartWithArrayOperator.php @@ -10,17 +10,33 @@ use Rx\ObserverInterface; use Rx\SchedulerInterface; +/** + * @template T + */ final class StartWithArrayOperator implements OperatorInterface { + /** + * @var array + */ private $startArray; + + /** + * @var SchedulerInterface + */ private $scheduler; + /** + * @param array $startArray + */ public function __construct(array $startArray, SchedulerInterface $scheduler) { $this->startArray = $startArray; $this->scheduler = $scheduler; } + /** + * @param ObservableInterface $observable + */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface { return Observable::fromArray($this->startArray, $this->scheduler)->concat($observable)->subscribe($observer); diff --git a/src/Operator/SubscribeOnOperator.php b/src/Operator/SubscribeOnOperator.php index 473f4dcb..72b84611 100644 --- a/src/Operator/SubscribeOnOperator.php +++ b/src/Operator/SubscribeOnOperator.php @@ -14,6 +14,9 @@ final class SubscribeOnOperator implements OperatorInterface { + /** + * @var SchedulerInterface + */ private $scheduler; public function __construct(SchedulerInterface $scheduler) diff --git a/src/Operator/SwitchFirstOperator.php b/src/Operator/SwitchFirstOperator.php index 1dafe55c..da446fb8 100644 --- a/src/Operator/SwitchFirstOperator.php +++ b/src/Operator/SwitchFirstOperator.php @@ -14,7 +14,14 @@ final class SwitchFirstOperator implements OperatorInterface { + /** + * @var bool + */ private $isStopped = false; + + /** + * @var bool + */ private $hasCurrent = false; public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface diff --git a/src/Operator/TakeLastOperator.php b/src/Operator/TakeLastOperator.php index 81e3cae3..89515745 100644 --- a/src/Operator/TakeLastOperator.php +++ b/src/Operator/TakeLastOperator.php @@ -9,12 +9,15 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class TakeLastOperator implements OperatorInterface { /** @var integer */ private $count; - /** @var array */ + /** @var array */ private $items = []; public function __construct(int $count) @@ -29,7 +32,7 @@ public function __construct(int $count) public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface { $callbackObserver = new CallbackObserver( - function ($nextValue) use ($observer) { + function ($nextValue) { $this->items[] = $nextValue; if (count($this->items) > $this->count) { diff --git a/src/Operator/TakeOperator.php b/src/Operator/TakeOperator.php index f9585e96..d6bec3be 100644 --- a/src/Operator/TakeOperator.php +++ b/src/Operator/TakeOperator.php @@ -11,6 +11,9 @@ final class TakeOperator implements OperatorInterface { + /** + * @var int + */ private $count; public function __construct(int $count) diff --git a/src/Operator/TakeUntilOperator.php b/src/Operator/TakeUntilOperator.php index 4732bb7b..8c760e64 100644 --- a/src/Operator/TakeUntilOperator.php +++ b/src/Operator/TakeUntilOperator.php @@ -10,10 +10,19 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class TakeUntilOperator implements OperatorInterface { + /** + * @var ObservableInterface + */ private $other; + /** + * @param ObservableInterface $other + */ public function __construct(ObservableInterface $other) { $this->other = $other; diff --git a/src/Operator/TakeWhileOperator.php b/src/Operator/TakeWhileOperator.php index 02e21e6f..b3f8e58e 100644 --- a/src/Operator/TakeWhileOperator.php +++ b/src/Operator/TakeWhileOperator.php @@ -9,10 +9,19 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class TakeWhileOperator implements OperatorInterface { + /** + * @var (callable(T): bool) + */ private $predicate; + /** + * @param (callable(T): bool) $predicate + */ public function __construct(callable $predicate) { $this->predicate = $predicate; diff --git a/src/Operator/ThrottleOperator.php b/src/Operator/ThrottleOperator.php index 41dc9684..5ba43052 100644 --- a/src/Operator/ThrottleOperator.php +++ b/src/Operator/ThrottleOperator.php @@ -16,12 +16,24 @@ final class ThrottleOperator implements OperatorInterface { + /** + * @var int + */ private $nextSend = 0; + /** + * @var int + */ private $throttleTime = 0; + /** + * @var bool + */ private $completed = false; + /** + * @var SchedulerInterface + */ private $scheduler; public function __construct(int $debounceTime, SchedulerInterface $scheduler) @@ -30,6 +42,10 @@ public function __construct(int $debounceTime, SchedulerInterface $scheduler) $this->scheduler = $scheduler; } + /** + * @template T + * @param ObservableInterface $observable + */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface { $innerDisp = new SerialDisposable(); @@ -44,8 +60,11 @@ function ($x) use ($innerDisp, $observer) { return; } - $newDisp = Observable::of($x, $this->scheduler) - ->delay($this->nextSend - $now, $this->scheduler) + /** + * @var Observable $observable + */ + $observable = Observable::of($x, $this->scheduler); + $newDisp = $observable->delay($this->nextSend - $now, $this->scheduler) ->subscribe(new CallbackObserver( function ($x) use ($observer) { $observer->onNext($x); diff --git a/src/Operator/TimeoutOperator.php b/src/Operator/TimeoutOperator.php index 4802f805..4619a415 100644 --- a/src/Operator/TimeoutOperator.php +++ b/src/Operator/TimeoutOperator.php @@ -14,23 +14,34 @@ use Rx\AsyncSchedulerInterface; use Rx\Exception\TimeoutException; +/** + * @template T + */ final class TimeoutOperator implements OperatorInterface { + /** + * @var int + */ private $timeout; + /** + * @var AsyncSchedulerInterface + */ private $scheduler; + /** + * @var ObservableInterface> + */ private $timeoutObservable; + /** + * @param ?ObservableInterface $timeoutObservable + */ public function __construct(int $timeout, ObservableInterface $timeoutObservable = null, AsyncSchedulerInterface $scheduler) { $this->timeout = $timeout; $this->scheduler = $scheduler; - $this->timeoutObservable = $timeoutObservable; - - if ($this->timeoutObservable === null) { - $this->timeoutObservable = new ErrorObservable(new TimeoutException('timeout'), $scheduler); - } + $this->timeoutObservable = $timeoutObservable ?: new ErrorObservable(new TimeoutException('timeout'), $scheduler); } /** diff --git a/src/Operator/TimestampOperator.php b/src/Operator/TimestampOperator.php index 7dbddf2e..27544259 100644 --- a/src/Operator/TimestampOperator.php +++ b/src/Operator/TimestampOperator.php @@ -11,11 +11,17 @@ use Rx\SchedulerInterface; use Rx\Timestamped; +/** + * @template T + */ final class TimestampOperator implements OperatorInterface { + /** + * @var SchedulerInterface + */ private $scheduler; - public function __construct(SchedulerInterface $scheduler = null) + public function __construct(SchedulerInterface $scheduler) { $this->scheduler = $scheduler; } diff --git a/src/Operator/ToArrayOperator.php b/src/Operator/ToArrayOperator.php index 19c5acdc..7ca09bd8 100644 --- a/src/Operator/ToArrayOperator.php +++ b/src/Operator/ToArrayOperator.php @@ -9,9 +9,12 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + */ final class ToArrayOperator implements OperatorInterface { - /** @var array */ + /** @var array */ private $arr = []; public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface diff --git a/src/Operator/WithLatestFromOperator.php b/src/Operator/WithLatestFromOperator.php index 5062fea4..b0633e2a 100644 --- a/src/Operator/WithLatestFromOperator.php +++ b/src/Operator/WithLatestFromOperator.php @@ -10,14 +10,20 @@ use Rx\ObservableInterface; use Rx\ObserverInterface; +/** + * @template T + */ final class WithLatestFromOperator implements OperatorInterface { - /** @var ObservableInterface[] */ + /** @var array> */ private $observables; /** @var callable */ private $resultSelector; + /** + * @param array> $observables + */ public function __construct(array $observables, callable $resultSelector = null) { if (null === $resultSelector) { diff --git a/src/Operator/ZipOperator.php b/src/Operator/ZipOperator.php index 674661bd..68d32e49 100644 --- a/src/Operator/ZipOperator.php +++ b/src/Operator/ZipOperator.php @@ -10,15 +10,21 @@ use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; +/** + * @template T + * @template TValue + */ final class ZipOperator implements OperatorInterface { - /** @var ObservableInterface[] */ + /** + * @var array> + */ private $sources; /** @var callable */ private $resultSelector; - /** @var \SplQueue[] */ + /** @var array<\SplQueue> */ private $queues = []; /** @var int */ @@ -30,6 +36,9 @@ final class ZipOperator implements OperatorInterface /** @var bool[] */ private $completed = []; + /** + * @param array> $sources + */ public function __construct(array $sources, callable $resultSelector = null) { $this->sources = $sources; diff --git a/src/React/Promise.php b/src/React/Promise.php index bd384191..d480b2a0 100644 --- a/src/React/Promise.php +++ b/src/React/Promise.php @@ -2,55 +2,64 @@ namespace Rx\React; -use React\Promise\Promise as ReactPromise; use React\Promise\PromiseInterface; use Rx\Disposable\CallbackDisposable; +use Rx\DisposableInterface; use Rx\ObservableInterface; use Rx\Observable; use Rx\Observable\AnonymousObservable; use Rx\Subject\AsyncSubject; use React\Promise\Deferred; use Throwable; +use function React\Promise\reject; +use function React\Promise\resolve; +/** + * @template T + */ final class Promise { /** - * @param mixed $value - * @return ReactPromise A promise resolved to $value + * @param T $value + * @return PromiseInterface A promise resolved to $value */ - public static function resolved($value): ReactPromise + public static function resolved($value): PromiseInterface { - $d = new Deferred(); - $d->resolve($value); - return $d->promise(); + return resolve($value); } /** * @param mixed $exception - * @return ReactPromise A promise rejected with $exception + * @return PromiseInterface A promise rejected with $exception */ - public static function rejected($exception): ReactPromise + public static function rejected($exception): PromiseInterface { - $d = new Deferred(); - $d->reject($exception instanceof Throwable ? $exception : new RejectedPromiseException($exception)); - return $d->promise(); + return reject($exception instanceof Throwable ? $exception : new RejectedPromiseException($exception)); } /** * Converts an existing observable sequence to React Promise * - * @param ObservableInterface $observable - * @param Deferred $deferred - * @return ReactPromise + * @template X + * @param ObservableInterface $observable + * @param ?Deferred $deferred + * @return PromiseInterface * @throws \InvalidArgumentException */ - public static function fromObservable(ObservableInterface $observable, Deferred $deferred = null): ReactPromise + public static function fromObservable(ObservableInterface $observable, Deferred $deferred = null): PromiseInterface { - + /** + * @var ?DisposableInterface $subscription + */ + $subscription = null; $d = $deferred ?: new Deferred(function () use (&$subscription) { + assert($subscription instanceof DisposableInterface); $subscription->dispose(); }); + /** + * @var X $value + */ $value = null; $subscription = $observable->subscribe( @@ -71,8 +80,9 @@ function () use ($d, &$value) { /** * Converts a Promise to an Observable sequence * - * @param PromiseInterface $promise - * @return Observable + * @template X + * @param PromiseInterface $promise + * @return Observable * @throws \InvalidArgumentException */ public static function toObservable(PromiseInterface $promise): Observable @@ -84,8 +94,7 @@ function ($value) use ($subject) { $subject->onNext($value); $subject->onCompleted(); }, - function ($error) use ($subject) { - $error = $error instanceof \Throwable ? $error : new RejectedPromiseException($error); + function (\Throwable $error) use ($subject) { $subject->onError($error); } ); diff --git a/src/React/PromiseFactory.php b/src/React/PromiseFactory.php index 7d7225ec..e31838f1 100644 --- a/src/React/PromiseFactory.php +++ b/src/React/PromiseFactory.php @@ -2,23 +2,25 @@ namespace Rx\React; +use React\Promise\PromiseInterface; use Rx\Observable; +use Rx\ObservableInterface; final class PromiseFactory { /** * Returns an observable sequence that invokes the specified factory function whenever a new observer subscribes. * - * @param callable $factory - * @return Observable + * @template T + * @param (callable(): PromiseInterface) $factory + * @return Observable * @throws \InvalidArgumentException */ public static function toObservable(callable $factory): Observable { - $observableFactory = function () use ($factory) { + /** @phpstan-ignore-next-line */ + return Observable::defer(static function () use ($factory): ObservableInterface { return Promise::toObservable($factory()); - }; - - return Observable::defer($observableFactory); + }); } } diff --git a/src/React/RejectedPromiseException.php b/src/React/RejectedPromiseException.php index e82ba010..b90e2dad 100644 --- a/src/React/RejectedPromiseException.php +++ b/src/React/RejectedPromiseException.php @@ -4,10 +4,14 @@ class RejectedPromiseException extends \Exception { + /** + * @var mixed + */ private $rejectValue; /** * RejectedPromiseException constructor. + * @param mixed $rejectValue */ public function __construct($rejectValue) { @@ -17,7 +21,7 @@ public function __construct($rejectValue) } /** - * @return string + * @return mixed */ public function getRejectValue() { diff --git a/src/Scheduler.php b/src/Scheduler.php index c37b672d..8a7b4029 100644 --- a/src/Scheduler.php +++ b/src/Scheduler.php @@ -8,12 +8,34 @@ final class Scheduler { + /** + * @var null|SchedulerInterface|AsyncSchedulerInterface + */ private static $default; + + /** + * @var ?AsyncSchedulerInterface + */ private static $async; + + /** + * @var ?ImmediateScheduler + */ private static $immediate; + + /** + * @var (callable(): SchedulerInterface) + */ private static $defaultFactory; + + /** + * @var (callable(): AsyncSchedulerInterface) + */ private static $asyncFactory; + /** + * @return SchedulerInterface|AsyncSchedulerInterface + */ public static function getDefault(): SchedulerInterface { if (static::$default) { @@ -29,6 +51,10 @@ public static function getDefault(): SchedulerInterface return static::$default; } + /** + * @param (callable(): SchedulerInterface) $factory + * @return void + */ public static function setDefaultFactory(callable $factory) { if (static::$default !== null) { @@ -40,12 +66,14 @@ public static function setDefaultFactory(callable $factory) public static function getAsync(): AsyncSchedulerInterface { - if (static::$async) { + if (static::$async instanceof AsyncSchedulerInterface) { return static::$async; } if (static::$asyncFactory === null && static::getDefault() instanceof AsyncSchedulerInterface) { + assert(static::$default instanceof AsyncSchedulerInterface); static::$async = static::$default; + assert(static::$async instanceof AsyncSchedulerInterface); return static::$async; } @@ -58,6 +86,10 @@ public static function getAsync(): AsyncSchedulerInterface return static::$async; } + /** + * @param (callable(): AsyncSchedulerInterface) $factory + * @return void + */ public static function setAsyncFactory(callable $factory) { if (static::$async !== null) { @@ -72,6 +104,8 @@ public static function getImmediate(): ImmediateScheduler if (!static::$immediate) { static::$immediate = new ImmediateScheduler(); } + + assert(self::$immediate instanceof ImmediateScheduler); return self::$immediate; } } diff --git a/src/Scheduler/EventLoopScheduler.php b/src/Scheduler/EventLoopScheduler.php index 98059a1b..6c8c6bc5 100644 --- a/src/Scheduler/EventLoopScheduler.php +++ b/src/Scheduler/EventLoopScheduler.php @@ -12,12 +12,24 @@ final class EventLoopScheduler extends VirtualTimeScheduler { + /** + * @var int + */ private $nextTimer = PHP_INT_MAX; + /** + * @var bool + */ private $insideInvoke = false; + /** + * @var callable + */ private $delayCallback; + /** + * @var DisposableInterface + */ private $currentTimer; /** @@ -42,6 +54,9 @@ function ($ms, $callable) use ($timerCallableOrLoop) { }); } + /** + * @return void + */ private function scheduleStartup() { if ($this->insideInvoke) { diff --git a/src/Scheduler/InternalPriorityQueue.php b/src/Scheduler/InternalPriorityQueue.php new file mode 100644 index 00000000..1a31778c --- /dev/null +++ b/src/Scheduler/InternalPriorityQueue.php @@ -0,0 +1,58 @@ + + */ +class InternalPriorityQueue extends SplPriorityQueue +{ + /** + * use this value to "stabilize" the priority queue + * + * @var int + */ + private $serial = PHP_INT_MAX; + + /** + * @param ScheduledItem $item + * @param int $priority + * @return void + * Look at this later + * @phpstan-ignore-next-line + */ + public function insert($item, $priority) + { + /** + * Look at this later + * @phpstan-ignore-next-line + */ + parent::insert($item, [$priority, $this->serial--]); + } + + /** + * @param array{0: ScheduledItem, 1: int} $a + * @param array{0: ScheduledItem, 1: int} $b + * @return int + */ + #[ReturnTypeWillChange] + public function compare($a, $b) + { + $value = $b[0]->compareTo($a[0]); + + if (0 === $value) { + return $a[1] < $b[1] ? -1 : 1; + } + + return $value; + } +} diff --git a/src/Scheduler/PriorityQueue.php b/src/Scheduler/PriorityQueue.php index 88e8d9c8..91982ac3 100644 --- a/src/Scheduler/PriorityQueue.php +++ b/src/Scheduler/PriorityQueue.php @@ -9,6 +9,9 @@ class PriorityQueue { + /** + * @var InternalPriorityQueue + */ private $queue; public function __construct() @@ -16,12 +19,19 @@ public function __construct() $this->queue = new InternalPriorityQueue; } + /** + * @return void + */ public function enqueue(ScheduledItem $item) { + /** @phpstan-ignore-next-line */ $this->queue->insert($item, $item); } - public function remove($item) + /** + * @return bool + */ + public function remove(ScheduledItem $item) { if ($this->count() === 0) { return false; @@ -31,15 +41,27 @@ public function remove($item) $this->dequeue(); return true; } + + /** + * @var InternalPriorityQueue $newQueue + */ $newQueue = new InternalPriorityQueue(); $removed = false; foreach ($this->queue as $element) { + /** + * Look at this later + * @phpstan-ignore-next-line + */ if ($item === $element) { $removed = true; continue; } + /** + * Look at this later + * @phpstan-ignore-next-line + */ $newQueue->insert($element, $element); } @@ -48,44 +70,31 @@ public function remove($item) return $removed; } + /** + * @return int + */ public function count() { return $this->queue->count(); } + /** + * @return ScheduledItem + */ public function peek() { - return $this->queue->top(); + $return = $this->queue->top(); + assert($return instanceof ScheduledItem); + return $return; } + /** + * @return ScheduledItem + */ public function dequeue() { - return $this->queue->extract(); - } -} - -/** - * @internal - */ -class InternalPriorityQueue extends SplPriorityQueue -{ - // use this value to "stabilize" the priority queue - private $serial = PHP_INT_MAX; - - public function insert($item, $priority) - { - parent::insert($item, [$priority, $this->serial--]); - } - - #[ReturnTypeWillChange] - public function compare($a, $b) - { - $value = $b[0]->compareTo($a[0]); - - if (0 === $value) { - return $a[1] < $b[1] ? -1 : 1; - } - - return $value; + $return = $this->queue->extract(); + assert($return instanceof ScheduledItem); + return $return; } } diff --git a/src/Scheduler/ScheduledItem.php b/src/Scheduler/ScheduledItem.php index 5b8bcb79..3fa5f387 100644 --- a/src/Scheduler/ScheduledItem.php +++ b/src/Scheduler/ScheduledItem.php @@ -5,55 +5,101 @@ namespace Rx\Scheduler; use Rx\Disposable\SingleAssignmentDisposable; +use Rx\DisposableInterface; +use Rx\SchedulerInterface; class ScheduledItem { + /** + * @var SchedulerInterface + */ private $scheduler; + + /** + * @var mixed + */ private $state; + + /** + * @var (callable(SchedulerInterface, mixed): DisposableInterface) + */ private $action; + + /** + * @var int + */ private $dueTime; + + /** + * @var callable + */ private $comparer; + + /** + * @var SingleAssignmentDisposable + */ private $disposable; - public function __construct($scheduler, $state, $action, $dueTime, $comparer = null) + /** + * @param mixed $state + * @param (callable(SchedulerInterface, mixed): DisposableInterface) $action + * @param (callable(int, int): int) $comparer + */ + public function __construct(SchedulerInterface $scheduler, $state, callable $action, int $dueTime, callable $comparer = null) { $this->scheduler = $scheduler; $this->state = $state; $this->action = $action; $this->dueTime = $dueTime; - $this->comparer = $comparer ?: function ($a, $b) { + $this->comparer = $comparer ?: function (int $a, int $b) { return $a - $b; }; $this->disposable = new SingleAssignmentDisposable(); } + /** + * @return void + */ public function invoke() { $this->disposable->setDisposable($this->invokeCore()); } + /** + * @param ScheduledItem $other + * @return int + */ public function compareTo(ScheduledItem $other) { $comparer = $this->comparer; return $comparer($this->dueTime, $other->dueTime); } + /** + * @return bool + */ public function isCancelled() { return $this->disposable->isDisposed(); } - public function invokeCore() + public function invokeCore(): DisposableInterface { $action = $this->action; return $action($this->scheduler, $this->state); } + /** + * @return int + */ public function getDueTime() { return $this->dueTime; } + /** + * @return SingleAssignmentDisposable + */ public function getDisposable() { return $this->disposable; diff --git a/src/Scheduler/VirtualTimeScheduler.php b/src/Scheduler/VirtualTimeScheduler.php index 161723e2..824e5f4c 100644 --- a/src/Scheduler/VirtualTimeScheduler.php +++ b/src/Scheduler/VirtualTimeScheduler.php @@ -12,9 +12,24 @@ class VirtualTimeScheduler implements AsyncSchedulerInterface { + /** + * @var int + */ protected $clock; + + /** + * @var callable + */ protected $comparer; + + /** + * @var bool + */ protected $isEnabled = false; + + /** + * @var PriorityQueue + */ protected $queue; /** @@ -41,10 +56,9 @@ public function schedule(callable $action, $delay = 0): DisposableInterface public function scheduleRecursive(callable $action): DisposableInterface { - $goAgain = true; $disposable = new SerialDisposable(); - $recursiveAction = function () use ($action, &$goAgain, $disposable, &$recursiveAction) { + $recursiveAction = function () use ($action, $disposable, &$recursiveAction) { $disposable->setDisposable($this->schedule(function () use ($action, &$recursiveAction) { $action(function () use (&$recursiveAction) { $recursiveAction(); @@ -62,7 +76,7 @@ public function getClock(): int return $this->clock; } - public function scheduleAbsolute(int $dueTime, $action): DisposableInterface + public function scheduleAbsolute(int $dueTime, callable $action): DisposableInterface { $invokeAction = function ($scheduler, $action) { $action(); @@ -72,6 +86,9 @@ public function scheduleAbsolute(int $dueTime, $action): DisposableInterface return $this->scheduleAbsoluteWithState($action, $dueTime, $invokeAction); } + /** + * @param mixed $state + */ public function scheduleAbsoluteWithState($state, int $dueTime, callable $action): DisposableInterface { $queue = $this->queue; @@ -79,6 +96,7 @@ public function scheduleAbsoluteWithState($state, int $dueTime, callable $action $scheduledItem = null; $run = function ($scheduler, $state1) use ($action, &$scheduledItem, &$queue) { + assert($scheduledItem instanceof ScheduledItem); /** @phpstan-ignore-line */ $queue->remove($scheduledItem); return $action($scheduler, $state1); @@ -94,7 +112,10 @@ public function scheduleAbsoluteWithState($state, int $dueTime, callable $action }); } - public function scheduleRelativeWithState($state, $dueTime, $action): DisposableInterface + /** + * @param mixed $state + */ + public function scheduleRelativeWithState($state, int $dueTime, callable $action): DisposableInterface { $runAt = $this->now() + $dueTime; @@ -127,6 +148,9 @@ public function schedulePeriodic(callable $action, $delay, $period): DisposableI return $disposable; } + /** + * @return void + */ public function start() { if (!$this->isEnabled) { @@ -152,6 +176,9 @@ public function start() } } + /** + * @return ?ScheduledItem + */ public function getNext() { while ($this->queue->count() > 0) { diff --git a/src/SchedulerInterface.php b/src/SchedulerInterface.php index 4ebbbcb3..ea486389 100644 --- a/src/SchedulerInterface.php +++ b/src/SchedulerInterface.php @@ -8,7 +8,7 @@ interface SchedulerInterface { /** * @param callable $action - * @param $delay + * @param int $delay * * @return DisposableInterface */ @@ -24,16 +24,16 @@ public function scheduleRecursive(callable $action): DisposableInterface; /** * @param callable $action * @param int $delay - * @param $period + * @param int $period * - * @return mixed + * @return DisposableInterface */ public function schedulePeriodic(callable $action, $delay, $period): DisposableInterface; /** * Gets the current representation of now for the scheduler * - * @return mixed + * @return int */ public function now(): int; } diff --git a/src/Subject/AsyncSubject.php b/src/Subject/AsyncSubject.php index ef3200cc..b2b1e55c 100644 --- a/src/Subject/AsyncSubject.php +++ b/src/Subject/AsyncSubject.php @@ -9,13 +9,15 @@ use Rx\ObserverInterface; /** + * @template T + * @template-extends Subject * Class AsyncSubject * @package Rx\Subject */ class AsyncSubject extends Subject { /** - * @var + * @var T */ private $value; @@ -26,7 +28,7 @@ class AsyncSubject extends Subject private $valueSet = false; /** - * @return mixed + * @return T */ public function getValue() { @@ -34,7 +36,7 @@ public function getValue() } /** - * @param $value + * @param T $value */ public function onNext($value) { diff --git a/src/Subject/BehaviorSubject.php b/src/Subject/BehaviorSubject.php index 4729b75f..d8c991bb 100644 --- a/src/Subject/BehaviorSubject.php +++ b/src/Subject/BehaviorSubject.php @@ -5,17 +5,32 @@ namespace Rx\Subject; use Rx\DisposableInterface; +use Rx\Observable; +use Rx\ObservableInterface; use Rx\ObserverInterface; +/** + * @template T + * @template-extends Subject + */ class BehaviorSubject extends Subject { + /** + * @var T|null + */ private $value; + /** + * @param T $initValue + */ public function __construct($initValue = null) { $this->value = $initValue; } + /** + * @return ?T + */ public function getValue() { return $this->value; diff --git a/src/Subject/InnerSubscriptionDisposable.php b/src/Subject/InnerSubscriptionDisposable.php index ccea81d7..66f70a0b 100644 --- a/src/Subject/InnerSubscriptionDisposable.php +++ b/src/Subject/InnerSubscriptionDisposable.php @@ -7,17 +7,34 @@ use Rx\DisposableInterface; use Rx\ObserverInterface; +/** + * @template T + */ class InnerSubscriptionDisposable implements DisposableInterface { + /** + * @var ?ObserverInterface + */ private $observer; + + /** + * @var Subject + */ private $subject; + /** + * @param Subject $subject + * @param ObserverInterface $observer + */ public function __construct(Subject $subject, ObserverInterface $observer) { $this->subject = $subject; $this->observer = $observer; } + /** + * @return void + */ public function dispose() { if ($this->subject->isDisposed()) { diff --git a/src/Subject/ReplaySubject.php b/src/Subject/ReplaySubject.php index e0ac85d8..493e53e8 100644 --- a/src/Subject/ReplaySubject.php +++ b/src/Subject/ReplaySubject.php @@ -6,12 +6,17 @@ use Rx\Disposable\CallbackDisposable; use Rx\DisposableInterface; +use Rx\Observable; +use Rx\ObservableInterface; use Rx\Observer\ScheduledObserver; use Rx\ObserverInterface; use Rx\Scheduler; use Rx\SchedulerInterface; /** + * @template T + * @template-extends Subject + * * Represents an object that is both an observable sequence as well as an observer. * Each notification is broadcasted to all subscribed and future observers, subject to buffer trimming policies. */ @@ -23,7 +28,7 @@ class ReplaySubject extends Subject /** @var int */ private $windowSize; - /** @var array */ + /** @var array */ private $queue = []; /** @var int */ @@ -69,7 +74,7 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface } if ($this->hasError) { - $so->onError($this->exception); + $so->onError($this->exception); /** @phpstan-ignore-line */ } else { if ($this->isStopped) { $so->onCompleted(); @@ -81,6 +86,10 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface return $subscription; } + /** + * @param T $value + * @return void + */ public function onNext($value) { $this->assertNotDisposed(); @@ -144,7 +153,12 @@ public function onError(\Throwable $exception) $this->observers = []; } - private function createRemovableDisposable($subject, $observer): DisposableInterface + /** + * @param Subject $subject + * @param ScheduledObserver $observer + * @return DisposableInterface + */ + private function createRemovableDisposable(Subject $subject, ScheduledObserver $observer): DisposableInterface { return new CallbackDisposable(function () use ($observer, $subject) { $observer->dispose(); @@ -154,6 +168,9 @@ private function createRemovableDisposable($subject, $observer): DisposableInter }); } + /** + * @return void + */ private function trim() { if (count($this->queue) > $this->bufferSize) { diff --git a/src/Subject/Subject.php b/src/Subject/Subject.php index f5e2cdcb..73ce6cdf 100644 --- a/src/Subject/Subject.php +++ b/src/Subject/Subject.php @@ -8,13 +8,34 @@ use Rx\Disposable\EmptyDisposable; use Rx\Observable; use Rx\DisposableInterface; +use Rx\ObservableInterface; use Rx\ObserverInterface; -class Subject extends Observable implements ObserverInterface, DisposableInterface +/** + * @template T + * @template-extends Observable + * @template-implements ObservableInterface + */ +class Subject extends Observable implements ObserverInterface, DisposableInterface, ObservableInterface { + /** + * @var ?\Throwable + */ protected $exception; + + /** + * @var bool + */ protected $isDisposed = false; + + /** + * @var bool + */ protected $isStopped = false; + + /** + * @var array + */ protected $observers = []; protected function _subscribe(ObserverInterface $observer): DisposableInterface @@ -38,16 +59,25 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface return new EmptyDisposable(); } + /** + * @return bool + */ public function isDisposed() { return $this->isDisposed; } + /** + * @return bool + */ public function hasObservers() { return count($this->observers) > 0; } + /** + * @return void + */ protected function assertNotDisposed() { if ($this->isDisposed) { @@ -55,6 +85,9 @@ protected function assertNotDisposed() } } + /** + * @return void + */ public function onCompleted() { $this->assertNotDisposed(); @@ -73,6 +106,9 @@ public function onCompleted() $this->observers = []; } + /** + * @return void + */ public function onError(\Throwable $exception) { $this->assertNotDisposed(); @@ -92,6 +128,10 @@ public function onError(\Throwable $exception) $this->observers = []; } + /** + * @param T $value + * @return void + */ public function onNext($value) { $this->assertNotDisposed(); @@ -106,6 +146,9 @@ public function onNext($value) } } + /** + * @return void + */ public function dispose() { $this->isDisposed = true; diff --git a/src/Testing/ColdObservable.php b/src/Testing/ColdObservable.php index fce41240..7391ad92 100644 --- a/src/Testing/ColdObservable.php +++ b/src/Testing/ColdObservable.php @@ -12,12 +12,30 @@ use Rx\Observable; use Rx\ObserverInterface; +/** + * @template T + * @template-extends Observable + */ class ColdObservable extends Observable { + /** + * @var TestScheduler + */ private $scheduler; + + /** + * @var array + */ private $messages; + + /** + * @var array + */ private $subscriptions = []; + /** + * @param array $messages + */ public function __construct(TestScheduler $scheduler, array $messages = []) { $this->scheduler = $scheduler; @@ -29,7 +47,6 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface $this->subscriptions[] = new Subscription($this->scheduler->getClock()); $index = count($this->subscriptions) - 1; - $currentObservable = $this; $disposable = new CompositeDisposable(); $scheduler = $this->scheduler; $isDisposed = false; @@ -38,8 +55,11 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface $notification = $message->getValue(); $time = $message->getTime(); - $schedule = function (Notification $innerNotification) use (&$disposable, &$currentObservable, $observer, $scheduler, $time, &$isDisposed) { + assert($notification instanceof Notification); + + $schedule = function (Notification $innerNotification) use (&$disposable, $observer, $scheduler, $time, &$isDisposed) { $disposable->add($scheduler->scheduleRelativeWithState(null, $time, function () use ($observer, $innerNotification, &$isDisposed) { + /** @phpstan-ignore-next-line */ if (!$isDisposed) { $innerNotification->accept($observer); } @@ -52,13 +72,16 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface $subscriptions = &$this->subscriptions; - return new CallbackDisposable(function () use (&$currentObservable, $index, $observer, $scheduler, &$subscriptions, &$isDisposed) { + return new CallbackDisposable(function () use ($index, $scheduler, &$subscriptions, &$isDisposed) { $isDisposed = true; $subscriptions[$index] = new Subscription($subscriptions[$index]->getSubscribed(), $scheduler->getClock()); }); } + /** + * @return array + */ public function getSubscriptions(): array { return $this->subscriptions; diff --git a/src/Testing/HotObservable.php b/src/Testing/HotObservable.php index a86bdfed..84469aeb 100644 --- a/src/Testing/HotObservable.php +++ b/src/Testing/HotObservable.php @@ -11,23 +11,39 @@ use Rx\Observable; use Rx\ObserverInterface; +/** + * @template T + * @template-extends Observable + */ class HotObservable extends Observable { + /** + * @var TestScheduler + */ private $scheduler; - private $messages; + /** + * @var array + */ private $subscriptions = []; + /** + * @var array + */ private $observers = []; + /** + * @param array $messages + */ public function __construct(TestScheduler $scheduler, array $messages) { $this->scheduler = $scheduler; - $this->messages = $messages; $currentObservable = $this; foreach ($messages as $message) { $time = $message->getTime(); $notification = $message->getValue(); + assert($notification instanceof Notification); + $schedule = function (Notification $innerNotification) use (&$currentObservable, $scheduler, $time) { $scheduler->scheduleAbsolute($time, function () use (&$currentObservable, $innerNotification) { $observers = $currentObservable->getObservers(); @@ -77,12 +93,17 @@ public function removeObserver(ObserverInterface $observer): bool /** * @internal + * + * @return array */ public function getObservers(): array { return $this->observers; } + /** + * @return array + */ public function getSubscriptions(): array { return $this->subscriptions; diff --git a/src/Testing/MockObserver.php b/src/Testing/MockObserver.php index a30a050c..b738b2c4 100644 --- a/src/Testing/MockObserver.php +++ b/src/Testing/MockObserver.php @@ -10,11 +10,19 @@ use Rx\ObserverInterface; /** + * @template T * Mock observer that records all messages. */ class MockObserver implements ObserverInterface { + /** + * @var TestScheduler + */ private $scheduler; + + /** + * @var array + */ private $messages = []; public function __construct(TestScheduler $scheduler) @@ -22,6 +30,10 @@ public function __construct(TestScheduler $scheduler) $this->scheduler = $scheduler; } + /** + * @param T $value + * @return void + */ public function onNext($value) { $this->messages[] = new Recorded( @@ -30,6 +42,10 @@ public function onNext($value) ); } + /** + * @param \Throwable $error + * @return void + */ public function onError(\Throwable $error) { $this->messages[] = new Recorded( @@ -38,6 +54,9 @@ public function onError(\Throwable $error) ); } + /** + * @return void + */ public function onCompleted() { $this->messages[] = new Recorded( @@ -46,6 +65,9 @@ public function onCompleted() ); } + /** + * @return array + */ public function getMessages() { return $this->messages; diff --git a/src/Testing/Recorded.php b/src/Testing/Recorded.php index 7d3192af..05616c18 100644 --- a/src/Testing/Recorded.php +++ b/src/Testing/Recorded.php @@ -6,6 +6,26 @@ class Recorded { + /** + * @var int + */ + private $time; + + /** + * @var mixed + */ + private $value; + + /** + * @var callable + */ + private $comparer; + + /** + * @param int $time + * @param mixed $value + * @param callable|null $comparer + */ public function __construct(int $time, $value, callable $comparer = null) { $this->time = $time; @@ -19,7 +39,7 @@ public function __construct(int $time, $value, callable $comparer = null) }; } - public function equals(Recorded $other) + public function equals(Recorded $other): bool { $comparer = $this->comparer; @@ -32,11 +52,14 @@ public function __toString() return $this->value . '@' . $this->time; } - public function getTime() + public function getTime(): int { return $this->time; } + /** + * @return mixed + */ public function getValue() { return $this->value; diff --git a/src/Testing/Subscription.php b/src/Testing/Subscription.php index c6915e2d..9d050cc1 100644 --- a/src/Testing/Subscription.php +++ b/src/Testing/Subscription.php @@ -6,7 +6,14 @@ class Subscription { + /** + * @var int + */ private $subscribed; + + /** + * @var int + */ private $unsubscribed; public function __construct(int $start, int $end = PHP_INT_MAX) @@ -15,18 +22,28 @@ public function __construct(int $start, int $end = PHP_INT_MAX) $this->unsubscribed = $end; } - public function equals(Subscription $other) + /** + * @param Subscription $other + * @return bool + */ + public function equals(Subscription $other): bool { return $this->subscribed === $other->subscribed && $this->unsubscribed === $other->unsubscribed; } - public function getSubscribed() + /** + * @return int + */ + public function getSubscribed(): int { return $this->subscribed; } - public function getUnsubscribed() + /** + * @return int + */ + public function getUnsubscribed(): int { return $this->unsubscribed; } diff --git a/src/Testing/TestScheduler.php b/src/Testing/TestScheduler.php index 4d7312b6..3de0c640 100644 --- a/src/Testing/TestScheduler.php +++ b/src/Testing/TestScheduler.php @@ -6,6 +6,8 @@ use Rx\Disposable\EmptyDisposable; use Rx\DisposableInterface; +use Rx\Observable; +use Rx\ObservableInterface; use Rx\ObserverInterface; use Rx\Scheduler; use Rx\Scheduler\VirtualTimeScheduler; @@ -23,6 +25,9 @@ public function __construct() }); } + /** + * @param mixed $state + */ public function scheduleAbsoluteWithState($state, int $dueTime, callable $action): DisposableInterface { if ($dueTime <= $this->clock) { @@ -32,17 +37,32 @@ public function scheduleAbsoluteWithState($state, int $dueTime, callable $action return parent::scheduleAbsoluteWithState($state, $dueTime, $action); } - public function startWithCreate($create): MockObserver + /** + * @template T + * @param (callable(): ObservableInterface) $create + * @return MockObserver + */ + public function startWithCreate(callable $create): MockObserver { return $this->startWithTiming($create); } - public function startWithDispose($create, $disposed): MockObserver + /** + * @template T + * @param (callable(): ObservableInterface) $create + * @return MockObserver + */ + public function startWithDispose(callable $create, int $disposed): MockObserver { return $this->startWithTiming($create, self::CREATED, self::SUBSCRIBED, $disposed); } - public function startWithTiming($create, $created = self::CREATED, $subscribed = self::SUBSCRIBED, $disposed = self::DISPOSED): ObserverInterface + /** + * @template T + * @param (callable(): ObservableInterface) $create + * @return MockObserver + */ + public function startWithTiming(callable $create, int $created = self::CREATED, int $subscribed = self::SUBSCRIBED, int $disposed = self::DISPOSED): MockObserver { $observer = new MockObserver($this); $source = null; @@ -55,12 +75,14 @@ public function startWithTiming($create, $created = self::CREATED, $subscribed = }); $this->scheduleAbsoluteWithState(null, $subscribed, function () use (&$observer, &$source, &$subscription) { + assert($source instanceof ObservableInterface); $subscription = $source->subscribe($observer); return new EmptyDisposable(); }); $this->scheduleAbsoluteWithState(null, $disposed, function () use (&$subscription) { + assert($subscription instanceof DisposableInterface); $subscription->dispose(); return new EmptyDisposable(); @@ -70,6 +92,9 @@ public function startWithTiming($create, $created = self::CREATED, $subscribed = return $observer; } + /** + * @phpstan-ignore-next-line + */ public function createObserver(): MockObserver { return new MockObserver($this); diff --git a/src/Testing/TestSubject.php b/src/Testing/TestSubject.php index 9be8929f..34d4b65f 100644 --- a/src/Testing/TestSubject.php +++ b/src/Testing/TestSubject.php @@ -10,6 +10,8 @@ use Rx\Subject\Subject; /** + * @template T + * @template-extends Subject * Class TestSubject * @package Rx\Testing */ @@ -18,11 +20,11 @@ class TestSubject extends Subject /** @var int */ private $subscribeCount; - /** @var ObserverInterface */ + /** @var ObserverInterface */ private $observer; - /* @var DisposableInterface[] */ - private $disposeOnMap; + /** @var array */ + private $disposeOnMap = []; public function __construct() { @@ -42,8 +44,9 @@ protected function _subscribe(ObserverInterface $observer): DisposableInterface } /** - * @param $value - * @param $disposable + * @param mixed $value + * @param DisposableInterface $disposable + * @return void */ public function disposeOn($value, DisposableInterface $disposable) { @@ -51,7 +54,7 @@ public function disposeOn($value, DisposableInterface $disposable) } /** - * @param $value + * @param T $value */ public function onNext($value) { diff --git a/src/Timestamped.php b/src/Timestamped.php index baa99f8b..92056d4e 100644 --- a/src/Timestamped.php +++ b/src/Timestamped.php @@ -17,13 +17,17 @@ class Timestamped * @param int $timestampMillis * @param mixed $value */ - public function __construct($timestampMillis, $value) + public function __construct(int $timestampMillis, $value) { $this->timestampMillis = $timestampMillis; $this->value = $value; } - public function equals($other) + /** + * @param Timestamped|mixed $other + * @return bool + */ + public function equals($other): bool { if ($this === $other) { return true; @@ -45,10 +49,7 @@ public function equals($other) return false; } - /** - * @return int - */ - public function getTimestampMillis() + public function getTimestampMillis(): int { return $this->timestampMillis; } diff --git a/test/Rx/Functional/Operator/GroupByUntilTest.php b/test/Rx/Functional/Operator/GroupByUntilTest.php index 762ba685..b8ca7660 100644 --- a/test/Rx/Functional/Operator/GroupByUntilTest.php +++ b/test/Rx/Functional/Operator/GroupByUntilTest.php @@ -4,6 +4,7 @@ namespace Rx\Functional\Operator; +use Rx\Disposable\EmptyDisposable; use Rx\Functional\FunctionalTestCase; use Rx\Notification; use Rx\Observable; @@ -565,7 +566,7 @@ public function groupByUntilInnerComplete() $this->scheduler->scheduleAbsolute( TestScheduler::SUBSCRIBED, function () use (&$outer, &$outerSubscription, &$inners, &$results, &$innerSubscriptions) { - $outerSubscription = $outer->subscribeCallback(function (GroupedObservable $group) use ( + $outerSubscription = $outer->subscribe(function (GroupedObservable $group) use ( &$inners, &$results ) { @@ -576,6 +577,8 @@ function () use (&$outer, &$outerSubscription, &$inners, &$results, &$innerSubsc $this->scheduler->scheduleRelativeWithState(null, 100, function () use ($group, $result) { $innerSubscriptions[$group->getKey()] = $group->subscribe($result); + + return new EmptyDisposable(); }); }); } @@ -787,6 +790,8 @@ function (GroupedObservable $group) use ( 100, function () use (&$innerSubscriptions, $group, $result) { $innerSubscriptions[$group->getKey()] = $group->subscribe($result); + + return new EmptyDisposable(); } ); }, diff --git a/test/Rx/Functional/Subject/ReplaySubjectTest.php b/test/Rx/Functional/Subject/ReplaySubjectTest.php index c7c966d9..d427a44c 100644 --- a/test/Rx/Functional/Subject/ReplaySubjectTest.php +++ b/test/Rx/Functional/Subject/ReplaySubjectTest.php @@ -4,6 +4,7 @@ namespace Rx\Functional\Subject; +use Rx\Disposable\EmptyDisposable; use Rx\Functional\FunctionalTestCase; use Rx\Observable; use Rx\Observer\CallbackObserver; @@ -36,35 +37,55 @@ public function testInfinite() $this->scheduler->scheduleAbsoluteWithState(null, 100, function () use (&$subject) { $subject = new ReplaySubject(3, 100, $this->scheduler); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 200, function () use (&$subscription, &$xs, &$subject) { $subscription = $xs->subscribe($subject); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 1000, function () use (&$subscription) { $subscription->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 300, function () use (&$subscription1, &$subject, &$results1) { $subscription1 = $subject->subscribe($results1); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 400, function () use (&$subscription2, &$subject, &$results2) { $subscription2 = $subject->subscribe($results2); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 900, function () use (&$subscription3, &$subject, &$results3) { $subscription3 = $subject->subscribe($results3); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 600, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 700, function () use (&$subscription2) { $subscription2->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 800, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 950, function () use (&$subscription3) { $subscription3->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->start(); @@ -125,35 +146,55 @@ public function testInfinite2() $this->scheduler->scheduleAbsoluteWithState(null, 100, function () use (&$subject) { $subject = new ReplaySubject(3, 100, $this->scheduler); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 200, function () use (&$subject, &$subscription, $xs) { $subscription = $xs->subscribe($subject); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 1000, function () use (&$subscription) { $subscription->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 300, function () use (&$subject, &$subscription1, &$results1) { $subscription1 = $subject->subscribe($results1); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 400, function () use (&$subject, &$subscription2, &$results2) { $subscription2 = $subject->subscribe($results2); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 900, function () use (&$subject, &$subscription3, &$results3) { $subscription3 = $subject->subscribe($results3); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 600, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 700, function () use (&$subscription2) { $subscription2->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 800, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 950, function () use (&$subscription3) { $subscription3->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->start(); @@ -209,35 +250,55 @@ public function testFinite() $this->scheduler->scheduleAbsoluteWithState(null, 100, function () use (&$subject) { $subject = new ReplaySubject(3, 100, $this->scheduler); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 200, function () use (&$subject, &$subscription, $xs) { $subscription = $xs->subscribe($subject); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 1000, function () use (&$subscription) { $subscription->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 300, function () use (&$subject, &$subscription1, &$results1) { $subscription1 = $subject->subscribe($results1); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 400, function () use (&$subject, &$subscription2, &$results2) { $subscription2 = $subject->subscribe($results2); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 900, function () use (&$subject, &$subscription3, &$results3) { $subscription3 = $subject->subscribe($results3); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 600, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 700, function () use (&$subscription2) { $subscription2->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 800, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 950, function () use (&$subscription3) { $subscription3->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->start(); @@ -286,35 +347,55 @@ public function testError() $this->scheduler->scheduleAbsoluteWithState(null, 100, function () use (&$subject) { $subject = new ReplaySubject(3, 100, $this->scheduler); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 200, function () use (&$subject, &$subscription, $xs) { $subscription = $xs->subscribe($subject); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 1000, function () use (&$subscription) { $subscription->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 300, function () use (&$subject, &$subscription1, &$results1) { $subscription1 = $subject->subscribe($results1); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 400, function () use (&$subject, &$subscription2, &$results2) { $subscription2 = $subject->subscribe($results2); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 900, function () use (&$subject, &$subscription3, &$results3) { $subscription3 = $subject->subscribe($results3); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 600, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 700, function () use (&$subscription2) { $subscription2->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 800, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 950, function () use (&$subscription3) { $subscription3->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->start(); @@ -354,35 +435,55 @@ public function testCanceled() $this->scheduler->scheduleAbsoluteWithState(null, 100, function () use (&$subject) { $subject = new ReplaySubject(3, 100, $this->scheduler); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 200, function () use (&$subject, &$subscription, $xs) { $subscription = $xs->subscribe($subject); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 1000, function () use (&$subscription) { $subscription->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 300, function () use (&$subject, &$subscription1, &$results1) { $subscription1 = $subject->subscribe($results1); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 400, function () use (&$subject, &$subscription2, &$results2) { $subscription2 = $subject->subscribe($results2); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 900, function () use (&$subject, &$subscription3, &$results3) { $subscription3 = $subject->subscribe($results3); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 600, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 700, function () use (&$subscription2) { $subscription2->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 800, function () use (&$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 950, function () use (&$subscription3) { $subscription3->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->start(); @@ -407,63 +508,97 @@ public function testDisposed() $this->scheduler->scheduleAbsoluteWithState(null, 100, function () use (&$subject) { $subject = new ReplaySubject(null, null, $this->scheduler); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 200, function () use (&$subject, &$subscription1, &$results1) { $subscription1 = $subject->subscribe($results1); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 300, function () use (&$subject, &$subscription2, &$results2) { $subscription2 = $subject->subscribe($results2); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 400, function () use (&$subject, &$subscription3, &$results3) { $subscription3 = $subject->subscribe($results3); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 500, function () use (&$subject, &$subscription1) { $subscription1->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 600, function () use (&$subject) { $subject->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 700, function () use (&$subscription2) { $subscription2->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 800, function () use (&$subscription3) { $subscription3->dispose(); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 150, function () use (&$subject) { $subject->onNext(1); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 250, function () use (&$subject) { $subject->onNext(2); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 350, function () use (&$subject) { $subject->onNext(3); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 450, function () use (&$subject) { $subject->onNext(4); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 550, function () use (&$subject) { $subject->onNext(5); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 650, function () use (&$subject) { $this->assertException(function () use (&$subject) { $subject->onNext(6); }); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 750, function () use (&$subject) { $this->assertException(function () use (&$subject) { $subject->onCompleted(); }); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 850, function () use (&$subject) { $this->assertException(function () use (&$subject) { $subject->onError(new \Exception()); }); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 950, function () use (&$subject) { $this->assertException(function () use (&$subject) { $subject->subscribe(new CallbackObserver()); }); + + return new EmptyDisposable(); }); $this->scheduler->start(); @@ -514,22 +649,34 @@ public function testDiesOut() $this->scheduler->scheduleAbsoluteWithState(null, 100, function () use (&$subject) { $subject = new ReplaySubject(9007199254740991, 100, $this->scheduler); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 200, function () use ($xs, &$subject) { $xs->subscribe($subject); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 300, function () use (&$subject, &$results1) { $subject->subscribe($results1); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 400, function () use (&$subject, &$results2) { $subject->subscribe($results2); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 600, function () use (&$subject, &$results3) { $subject->subscribe($results3); + + return new EmptyDisposable(); }); $this->scheduler->scheduleAbsoluteWithState(null, 900, function () use (&$subject, &$results4) { $subject->subscribe($results4); + + return new EmptyDisposable(); }); $this->scheduler->start(); diff --git a/test/Rx/ObservableTest.php b/test/Rx/ObservableTest.php index a7713d95..f386fe4d 100644 --- a/test/Rx/ObservableTest.php +++ b/test/Rx/ObservableTest.php @@ -24,7 +24,7 @@ public static function ofWasCalled() return static::$ofCalled; } - public static function of($value, SchedulerInterface $scheduler = null): ReturnObservable + public static function of($value, ?SchedulerInterface $scheduler = null): Observable { static::$ofCalled = true; return new ReturnObservable(123, new ImmediateScheduler()); diff --git a/test/Rx/Scheduler/PriorityQueueTest.php b/test/Rx/Scheduler/PriorityQueueTest.php index 7e9f800f..5b6727cf 100644 --- a/test/Rx/Scheduler/PriorityQueueTest.php +++ b/test/Rx/Scheduler/PriorityQueueTest.php @@ -4,6 +4,8 @@ namespace Rx\Scheduler; +use Rx\Disposable\EmptyDisposable; +use Rx\SchedulerInterface; use Rx\TestCase; class PriorityQueueTest extends TestCase @@ -32,7 +34,9 @@ public function it_should_remove_a_scheduled_item() private function createScheduledItem($dueTime) { - return new ScheduledItem(null, null, null, $dueTime, null); + return new ScheduledItem(new ImmediateScheduler(), null, function (SchedulerInterface $scheduler, $data) { + return new EmptyDisposable(); + }, $dueTime, null); } /** @@ -140,9 +144,10 @@ public function should_not_remove_nonexistent_item() $queue = new PriorityQueue(); $queue->remove( new ScheduledItem( - $this->createMock(ScheduledItem::class), + new ImmediateScheduler(), null, - function () { + function (SchedulerInterface $scheduler, $data) { + return new EmptyDisposable(); }, 0 ) diff --git a/test/types/array-observable.php b/test/types/array-observable.php new file mode 100644 index 00000000..42b97d5b --- /dev/null +++ b/test/types/array-observable.php @@ -0,0 +1,10 @@ +', new ArrayObservable([true, false], new ImmediateScheduler())); +assertType('Rx\Observable\ArrayObservable', new ArrayObservable([true, time()], new ImmediateScheduler())); diff --git a/test/types/observable-from-array.php b/test/types/observable-from-array.php new file mode 100644 index 00000000..02433025 --- /dev/null +++ b/test/types/observable-from-array.php @@ -0,0 +1,8 @@ +', Observable::fromArray([true, false])); diff --git a/test/types/observable-from-promise.php b/test/types/observable-from-promise.php new file mode 100644 index 00000000..dd432e78 --- /dev/null +++ b/test/types/observable-from-promise.php @@ -0,0 +1,9 @@ +', Observable::fromPromise(resolve(false))); diff --git a/test/types/observable-of.php b/test/types/observable-of.php new file mode 100644 index 00000000..0b8545d8 --- /dev/null +++ b/test/types/observable-of.php @@ -0,0 +1,13 @@ +', new ReturnObservable(true, new ImmediateScheduler())); +assertType('Rx\Observable', Observable::of(true)); +assertType('Rx\Observable', Observable::of(false)); +assertType('Rx\Observable', Observable::of(time())); diff --git a/test/types/observable-to-promise.php b/test/types/observable-to-promise.php new file mode 100644 index 00000000..3b295ede --- /dev/null +++ b/test/types/observable-to-promise.php @@ -0,0 +1,11 @@ +', Observable::of(true)->toPromise()); diff --git a/test/types/promise-to-observable.php b/test/types/promise-to-observable.php new file mode 100644 index 00000000..2443fdfa --- /dev/null +++ b/test/types/promise-to-observable.php @@ -0,0 +1,10 @@ +', Promise::toObservable(resolve(false)));