@@ -228,23 +228,14 @@ private function call(callable $callback)
228228 if ($ args === 0 ) {
229229 $ callback ();
230230 } else {
231- // Store a reference to all progress handlers (will be cleared when settled)
232- // This way, we can use a static progress callback that is not bound to this promise instance.
233- // This helps avoiding garbage cycles if the callback creates an Exception.
234- $ progress =& $ this ->progressHandlers ;
235-
236231 $ callback (
237232 function ($ value = null ) {
238233 $ this ->resolve ($ value );
239234 },
240235 function ($ reason = null ) {
241236 $ this ->reject ($ reason );
242237 },
243- \Closure::bind (function ($ update = null ) use (&$ progress ) {
244- foreach ($ progress as $ handler ) {
245- $ handler ($ update );
246- }
247- }, null )
238+ self ::notifier ($ this ->progressHandlers )
248239 );
249240 }
250241 } catch (\Throwable $ e ) {
@@ -253,4 +244,28 @@ function ($reason = null) {
253244 $ this ->reject ($ e );
254245 }
255246 }
247+
248+ /**
249+ * Creates a static progress callback that is not bound to a promise instance.
250+ *
251+ * Moving the closure creation to a static method allows us to create a
252+ * callback that is not bound to a promise instance. By passing its progress
253+ * handlers by reference, we can still execute them when requested and still
254+ * clear this reference when settling the promise. This helps avoiding
255+ * garbage cycles if any callback creates an Exception.
256+ *
257+ * These assumptions are covered by the test suite, so if you ever feel like
258+ * refactoring this, go ahead, any alternative suggestions are welcome!
259+ *
260+ * @param array $progressHandlers
261+ * @return callable
262+ */
263+ private static function notifier (&$ progressHandlers )
264+ {
265+ return function ($ update = null ) use (&$ progressHandlers ) {
266+ foreach ($ progressHandlers as $ handler ) {
267+ $ handler ($ update );
268+ }
269+ };
270+ }
256271}
0 commit comments