@@ -46,12 +46,37 @@ public function addTimer(Timer $timer):void {
4646 $ this ->timerList [] = $ timer ;
4747 }
4848
49+ /**
50+ * Track a Deferred within the loop lifecycle without attaching its
51+ * process callbacks to a Timer.
52+ *
53+ * This is useful for libraries that manage their own work scheduling but
54+ * still want the loop to halt when all tracked Deferred objects complete.
55+ */
56+ public function trackDeferred (Deferred $ deferred ):void {
57+ if ($ this ->isDeferredTracked ($ deferred )) {
58+ return ;
59+ }
60+
61+ $ deferred ->onComplete (
62+ function () use ($ deferred ) {
63+ $ this ->removeDeferred ($ deferred );
64+ });
65+
66+ $ this ->activeDeferred [] = $ deferred ;
67+ }
68+
69+ /**
70+ * @deprecated Prefer trackDeferred() when only completion tracking is
71+ * required. This method remains for Deferred objects whose process
72+ * callbacks should still be attached to a Timer.
73+ */
4974 public function addDeferredToTimer (
5075 Deferred $ deferred ,
5176 ?Timer $ timer = null
5277 ):void {
5378 $ timer = $ timer ?? $ this ->timerList [0 ];
54-
79+ $ this -> trackDeferred ( $ deferred );
5580 $ deferred ->onComplete (
5681 function () use ($ deferred , $ timer ) {
5782 $ this ->removeDeferredFromTimer (
@@ -63,11 +88,13 @@ function() use ($deferred, $timer) {
6388 foreach ($ deferred ->getProcessList () as $ function ) {
6489 $ timer ->addCallback ($ function );
6590 }
66-
67- $ this ->activeDeferred [] = $ deferred ;
6891 }
6992
7093
94+ /**
95+ * @deprecated Prefer removeDeferred() when no Timer callbacks were attached
96+ * by addDeferredToTimer().
97+ */
7198 public function removeDeferredFromTimer (
7299 Deferred $ deferred ,
73100 ?Timer $ timer = null
@@ -77,9 +104,14 @@ public function removeDeferredFromTimer(
77104 foreach ($ deferred ->getProcessList () as $ function ) {
78105 $ timer ->removeCallback ($ function );
79106 }
107+ $ this ->removeDeferred ($ deferred );
108+ }
109+
110+ public function removeDeferred (Deferred $ deferred ):void {
80111 $ activeDeferredIndex = array_search (
81112 $ deferred ,
82- $ this ->activeDeferred
113+ $ this ->activeDeferred ,
114+ true
83115 );
84116 if ($ activeDeferredIndex !== false ) {
85117 unset($ this ->activeDeferred [$ activeDeferredIndex ]);
@@ -173,4 +205,8 @@ private function executeTimers(TimerOrder $timerOrder):void {
173205 $ this ->trigger ($ item ["timer " ]);
174206 }
175207 }
208+
209+ private function isDeferredTracked (Deferred $ deferred ):bool {
210+ return array_search ($ deferred , $ this ->activeDeferred , true ) !== false ;
211+ }
176212}
0 commit comments