@@ -38,20 +38,22 @@ class DataLoader implements DataLoaderInterface
3838 /**
3939 * @var self[]
4040 */
41- private static $ instances = [];
41+ private static array $ activeInstances = [];
4242
4343 /**
4444 * @var PromiseAdapterInterface
4545 */
4646 private $ promiseAdapter ;
4747
48+ private static PromiseAdapterInterface |null $ staticPromiseAdapter = null ;
49+
4850 public function __construct (callable $ batchLoadFn , PromiseAdapterInterface $ promiseFactory , ?Option $ options = null )
4951 {
5052 $ this ->batchLoadFn = $ batchLoadFn ;
5153 $ this ->promiseAdapter = $ promiseFactory ;
54+ self ::$ staticPromiseAdapter ??= $ promiseFactory ;
5255 $ this ->options = $ options ?: new Option ();
5356 $ this ->promiseCache = $ this ->options ->getCacheMap ();
54- self ::$ instances [] = $ this ;
5557 }
5658
5759 /**
@@ -77,7 +79,7 @@ public function load($key)
7779 $ promise = $ this ->getPromiseAdapter ()->create (
7880 $ resolve ,
7981 $ reject ,
80- function () {
82+ static function () {
8183 // Cancel/abort any running operations like network connections, streams etc.
8284
8385 throw new \RuntimeException ('DataLoader destroyed before promise complete. ' );
@@ -91,6 +93,8 @@ function () {
9193 'promise ' => $ promise ,
9294 ];
9395
96+ self ::$ activeInstances [spl_object_id ($ this )] = $ this ;
97+
9498 // Determine if a dispatch of this queue should be scheduled.
9599 // A single dispatch should be scheduled per queue at the time when the
96100 // queue changes from "empty" to "full".
@@ -179,25 +183,21 @@ public function __destruct()
179183 }
180184 $ this ->await ();
181185 }
182- foreach (self ::$ instances as $ i => $ instance ) {
183- if ($ this !== $ instance ) {
184- continue ;
185- }
186- unset(self ::$ instances [$ i ]);
187- }
188186 }
189187
190188 protected function needProcess ()
191189 {
192190 return count ($ this ->queue ) > 0 ;
193191 }
194192
195- protected function process ()
193+ protected function process (): bool
196194 {
197195 if ($ this ->needProcess ()) {
198196 $ this ->getPromiseAdapter ()->await ();
199197 $ this ->dispatchQueue ();
198+ return true ;
200199 }
200+ return false ;
201201 }
202202
203203 protected function getPromiseAdapter ()
@@ -246,26 +246,20 @@ function ($reason) use (&$isPromiseCompleted, &$rejectedReason) {
246246 }
247247 }
248248
249- if (empty ( self ::$ instances ) ) {
249+ if (! self ::$ staticPromiseAdapter ) {
250250 throw new \RuntimeException ('Found no active DataLoader instance. ' );
251251 }
252252
253- return self ::$ instances [ 0 ]-> getPromiseAdapter () ->await ($ promise , $ unwrap );
253+ return self ::$ staticPromiseAdapter ->await ($ promise , $ unwrap );
254254 }
255255
256256 private static function awaitInstances ()
257257 {
258258 do {
259259 $ wait = false ;
260- $ dataLoaders = self ::$ instances ;
261260
262- foreach ($ dataLoaders as $ dataLoader ) {
263- if (!$ dataLoader || !$ dataLoader ->needProcess ()) {
264- $ wait |= false ;
265- continue ;
266- }
267- $ wait = true ;
268- $ dataLoader ->process ();
261+ foreach (self ::$ activeInstances as $ dataLoader ) {
262+ $ wait |= $ dataLoader ->process ();
269263 }
270264 } while ($ wait );
271265 }
@@ -305,6 +299,7 @@ private function dispatchQueue()
305299 // Take the current loader queue, replacing it with an empty queue.
306300 $ queue = $ this ->queue ;
307301 $ this ->queue = [];
302+ unset(self ::$ activeInstances [spl_object_id ($ this )]);
308303 $ queueLength = count ($ queue );
309304 // If a maxBatchSize was provided and the queue is longer, then segment the
310305 // queue into multiple batches, otherwise treat the queue as a single batch.
0 commit comments