@@ -13,7 +13,12 @@ function timeout(PromiseInterface $promise, $time, LoopInterface $loop)
1313 // thus leaving responsibility to the input promise.
1414 $ canceller = null ;
1515 if ($ promise instanceof CancellablePromiseInterface) {
16- $ canceller = array ($ promise , 'cancel ' );
16+ // pass promise by reference to clean reference after cancellation handler
17+ // has been invoked once in order to avoid garbage references in call stack.
18+ $ canceller = function () use (&$ promise ) {
19+ $ promise ->cancel ();
20+ $ promise = null ;
21+ };
1722 }
1823
1924 return new Promise (function ($ resolve , $ reject ) use ($ loop , $ time , $ promise ) {
@@ -38,12 +43,15 @@ function timeout(PromiseInterface $promise, $time, LoopInterface $loop)
3843 }
3944
4045 // start timeout timer which will cancel the input promise
41- $ timer = $ loop ->addTimer ($ time , function () use ($ time , $ promise , $ reject ) {
46+ $ timer = $ loop ->addTimer ($ time , function () use ($ time , & $ promise , $ reject ) {
4247 $ reject (new TimeoutException ($ time , 'Timed out after ' . $ time . ' seconds ' ));
4348
49+ // try to invoke cancellation handler of input promise and then clean
50+ // reference in order to avoid garbage references in call stack.
4451 if ($ promise instanceof CancellablePromiseInterface) {
4552 $ promise ->cancel ();
4653 }
54+ $ promise = null ;
4755 });
4856 }, $ canceller );
4957}
@@ -55,11 +63,12 @@ function resolve($time, LoopInterface $loop)
5563 $ timer = $ loop ->addTimer ($ time , function () use ($ time , $ resolve ) {
5664 $ resolve ($ time );
5765 });
58- }, function ($ resolve , $ reject , $ notify ) use (&$ timer , $ loop ) {
59- // cancelling this promise will cancel the timer and reject
66+ }, function () use (&$ timer , $ loop ) {
67+ // cancelling this promise will cancel the timer, clean the reference
68+ // in order to avoid garbage references in call stack and then reject.
6069 $ loop ->cancelTimer ($ timer );
70+ $ timer = null ;
6171
62- $ resolve = $ reject = $ notify = $ timer = $ loop = null ;
6372 throw new \RuntimeException ('Timer cancelled ' );
6473 });
6574}
0 commit comments