| 
<?php
 namespace React\Promise;
 
 function resolve($promiseOrValue = null)
 {
 if ($promiseOrValue instanceof ExtendedPromiseInterface) {
 return $promiseOrValue;
 }
 
 // Check is_object() first to avoid method_exists() triggering
 // class autoloaders if $promiseOrValue is a string.
 if (\is_object($promiseOrValue) && \method_exists($promiseOrValue, 'then')) {
 $canceller = null;
 
 if (\method_exists($promiseOrValue, 'cancel')) {
 $canceller = [$promiseOrValue, 'cancel'];
 }
 
 return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue) {
 $promiseOrValue->then($resolve, $reject, $notify);
 }, $canceller);
 }
 
 return new FulfilledPromise($promiseOrValue);
 }
 
 function reject($promiseOrValue = null)
 {
 if ($promiseOrValue instanceof PromiseInterface) {
 return resolve($promiseOrValue)->then(function ($value) {
 return new RejectedPromise($value);
 });
 }
 
 return new RejectedPromise($promiseOrValue);
 }
 
 function all($promisesOrValues)
 {
 return map($promisesOrValues, function ($val) {
 return $val;
 });
 }
 
 function race($promisesOrValues)
 {
 $cancellationQueue = new CancellationQueue();
 $cancellationQueue->enqueue($promisesOrValues);
 
 return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue) {
 resolve($promisesOrValues)
 ->done(function ($array) use ($cancellationQueue, $resolve, $reject, $notify) {
 if (!is_array($array) || !$array) {
 $resolve();
 return;
 }
 
 foreach ($array as $promiseOrValue) {
 $cancellationQueue->enqueue($promiseOrValue);
 
 resolve($promiseOrValue)
 ->done($resolve, $reject, $notify);
 }
 }, $reject, $notify);
 }, $cancellationQueue);
 }
 
 function any($promisesOrValues)
 {
 return some($promisesOrValues, 1)
 ->then(function ($val) {
 return \array_shift($val);
 });
 }
 
 function some($promisesOrValues, $howMany)
 {
 $cancellationQueue = new CancellationQueue();
 $cancellationQueue->enqueue($promisesOrValues);
 
 return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue) {
 resolve($promisesOrValues)
 ->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify) {
 if (!\is_array($array) || $howMany < 1) {
 $resolve([]);
 return;
 }
 
 $len = \count($array);
 
 if ($len < $howMany) {
 throw new Exception\LengthException(
 \sprintf(
 'Input array must contain at least %d item%s but contains only %s item%s.',
 $howMany,
 1 === $howMany ? '' : 's',
 $len,
 1 === $len ? '' : 's'
 )
 );
 }
 
 $toResolve = $howMany;
 $toReject  = ($len - $toResolve) + 1;
 $values    = [];
 $reasons   = [];
 
 foreach ($array as $i => $promiseOrValue) {
 $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) {
 if ($toResolve < 1 || $toReject < 1) {
 return;
 }
 
 $values[$i] = $val;
 
 if (0 === --$toResolve) {
 $resolve($values);
 }
 };
 
 $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) {
 if ($toResolve < 1 || $toReject < 1) {
 return;
 }
 
 $reasons[$i] = $reason;
 
 if (0 === --$toReject) {
 $reject($reasons);
 }
 };
 
 $cancellationQueue->enqueue($promiseOrValue);
 
 resolve($promiseOrValue)
 ->done($fulfiller, $rejecter, $notify);
 }
 }, $reject, $notify);
 }, $cancellationQueue);
 }
 
 function map($promisesOrValues, callable $mapFunc)
 {
 $cancellationQueue = new CancellationQueue();
 $cancellationQueue->enqueue($promisesOrValues);
 
 return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue) {
 resolve($promisesOrValues)
 ->done(function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify) {
 if (!\is_array($array) || !$array) {
 $resolve([]);
 return;
 }
 
 $toResolve = \count($array);
 $values    = [];
 
 foreach ($array as $i => $promiseOrValue) {
 $cancellationQueue->enqueue($promiseOrValue);
 $values[$i] = null;
 
 resolve($promiseOrValue)
 ->then($mapFunc)
 ->done(
 function ($mapped) use ($i, &$values, &$toResolve, $resolve) {
 $values[$i] = $mapped;
 
 if (0 === --$toResolve) {
 $resolve($values);
 }
 },
 $reject,
 $notify
 );
 }
 }, $reject, $notify);
 }, $cancellationQueue);
 }
 
 function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null)
 {
 $cancellationQueue = new CancellationQueue();
 $cancellationQueue->enqueue($promisesOrValues);
 
 return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue) {
 resolve($promisesOrValues)
 ->done(function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify) {
 if (!\is_array($array)) {
 $array = [];
 }
 
 $total = \count($array);
 $i = 0;
 
 // Wrap the supplied $reduceFunc with one that handles promises and then
 // delegates to the supplied.
 $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $cancellationQueue, $total, &$i) {
 $cancellationQueue->enqueue($val);
 
 return $current
 ->then(function ($c) use ($reduceFunc, $total, &$i, $val) {
 return resolve($val)
 ->then(function ($value) use ($reduceFunc, $total, &$i, $c) {
 return $reduceFunc($c, $value, $i++, $total);
 });
 });
 };
 
 $cancellationQueue->enqueue($initialValue);
 
 \array_reduce($array, $wrappedReduceFunc, resolve($initialValue))
 ->done($resolve, $reject, $notify);
 }, $reject, $notify);
 }, $cancellationQueue);
 }
 
 // Internal functions
 function _checkTypehint(callable $callback, $object)
 {
 if (!\is_object($object)) {
 return true;
 }
 
 if (\is_array($callback)) {
 $callbackReflection = new \ReflectionMethod($callback[0], $callback[1]);
 } elseif (\is_object($callback) && !$callback instanceof \Closure) {
 $callbackReflection = new \ReflectionMethod($callback, '__invoke');
 } else {
 $callbackReflection = new \ReflectionFunction($callback);
 }
 
 $parameters = $callbackReflection->getParameters();
 
 if (!isset($parameters[0])) {
 return true;
 }
 
 $expectedException = $parameters[0];
 
 if (!$expectedException->getClass()) {
 return true;
 }
 
 return $expectedException->getClass()->isInstance($object);
 }
 
 |