Execute a callable with dependencies.

@param callable $callable
@param array    $args
@param object   $context

@return  mixed

@throws DependencyResolutionException
@throws \ReflectionException
969737
public function execute($callable, array $args = [], $context = null)
    {
        if ($callable instanceof \Closure) {
            $ref = new \ReflectionObject($callable);

            $args = $this->getMethodArgs($ref->getMethod('__invoke'), $args);
        } else {
            if (is_string($callable)) {
                $callable = explode('::', $callable);
            }

            list($object, $method) = $callable;

            $ref = new \ReflectionClass($object);

            $args = $this->getMethodArgs($ref->getMethod($method), $args);
        }

        $closure = function () use ($args, $callable) {
            switch (count($args)) {
                case 0:
                    return $callable();
                case 1:
                    return $callable($args[0]);
                case 2:
                    return $callable($args[0], $args[1]);
                case 3:
                    return $callable($args[0], $args[1], $args[2]);
                case 4:
                    return $callable($args[0], $args[1], $args[2], $args[3]);
                default:
                    return call_user_func_array($callable, $args);
            }
        };

        if ($context) {
            $closure = $closure->bindTo($context, $context);
        }

        return $closure();
    }
534458
public static function sudo(callable $callable, array $arguments = array())
    {
        // don't do anything under Windows
        if (FileSystem::getOsIdentifier() === FileSystem::OS_IDENTIFIER_WIN) {
            return call_user_func_array($callable, $arguments);
        }

        // get the current user user pair (super user and effective user)
        $currentUserId = (integer) posix_geteuid();
        $superUserId = (integer) posix_getuid();

        // temporarily switch to the super user
        posix_seteuid($superUserId);

        // execute the callable
        $result = call_user_func_array($callable, $arguments);

        // switch back to the effective user
        posix_seteuid($currentUserId);

        return $result;
    }
344195
static function resolveCallableWithArgs(callable $callable, $parameters)
    {
        if ($parameters instanceof \Traversable)
            $parameters = \Poirot\Std\cast($parameters)->toArray();


        $reflection       = self::makeReflectFromCallable($callable);
        $matchedArguments = self::resolveArgsForReflection($reflection, $parameters);

        if (!empty($parameters) && empty($matchedArguments))
            // In Case That Fun Has No Any Argument.
            // exp. func() { $args = func_get_args() ..
            $matchedArguments = $parameters;

        $callbackResolved = function() use ($callable, $matchedArguments) {
            return call_user_func_array($callable, $matchedArguments);
        };

        return $callbackResolved;
    }
798431
public function withTransaction(callable $callable)
    {
        try {
            $nested = $this->transactionStarted;
            if (!$nested) {
                $this->startTransaction();
            }
            $this->transactionStarted = true;
            $result = $callable();
            if (!$nested) {
                $this->commit();
            }
            $this->transactionStarted = $nested;
            return $result;
        } catch (Throwable $e) {
            if ($this->transactionStarted) {
                $this->rollback();
                $this->transactionStarted = false;
            }
            throw $e;
        }
    }
685889
public function setCallable($callable)
    {
        $matches = array();
        if (is_string($callable) && preg_match('!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!', $callable, $matches)) {
            $class = $matches[1];
            $method = $matches[2];
            $callable = function() use ($class, $method) {
                static $obj = null;
                if ($obj === null) {
                    $obj = new $class;
                }
                return call_user_func_array(array($obj, $method), func_get_args());
            };
        }

        if (!is_callable($callable)) {
            throw new \InvalidArgumentException('Route callable must be callable');
        }

        $this->callable = $callable;
    }
564215
public static function multiply(callable ...$args): callable
    {
        $product = function ($x, ... $args) {
            $function = 1;
            foreach ($args as $arg) {
                $function *= $arg($x);
            }
            return $function;
        };

        return function ($x) use ($args, $product) {
            return $product(...array_merge([$x], $args));
        };
    }
755183
protected function callListener(callable $listener, array $args = [])
    {
        switch (count($args)) {
            case 0:
                return call_user_func($listener);
            case 1:
                return call_user_func($listener, $args[0]);
            case 2:
                return call_user_func($listener, $args[0], $args[1]);
            case 3:
                return call_user_func($listener, $args[0], $args[1], $args[2]);
            case 4:
                return call_user_func($listener, $args[0], $args[1], $args[2], $args[3]);
        }

        return call_user_func_array($listener, $args);
    }
1064567
public static function fromCallable($callable)
    {
        if (!is_callable($callable))
        {
            throw new \InvalidArgumentException('You must provide a vaild PHP callable.');
        }
        elseif (is_string($callable) && strpos($callable, '::') > 0)
        {
            $callable = explode('::', $callable);
        }

        if (is_array($callable))
        {
            list($class, $method) = $callable;
            $reflection = new \ReflectionMethod($class, $method);
        }
        else
        {
            $reflection = new \ReflectionFunction($callable);
        }

        return new static($reflection);
    }
284138
protected function callControllerCallable(callable $callable, array $parameters = [])
    {
        try {
            return $this->prepareResponse(
                $this->call($callable, $parameters)
            );
        } catch (HttpResponseException $e) {
            return $e->getResponse();
        }
    }
190273
public function buildExecutable($callableOrMethodStr)
    {
        try {
            list($reflFunc, $invocationObj) = $this->buildExecutableStruct($callableOrMethodStr);
        } catch (\ReflectionException $e) {
            throw InjectionException::fromInvalidCallable(
                $this->inProgressMakes,
                $callableOrMethodStr,
                $e
            );
        }

        return new Executable($reflFunc, $invocationObj);
    }
628865
public function dependencyCall($type, $name, array $args = array())
    {
        switch($type)
        {
            case 'service':
                return $this->get($name);
                break;
            case 'callable':
                return $this->__call($name, $args);
                break;
            case 'factory':
                return $this->create($name, $args);
                break;
        }
    }
1334658
public function map(callable $callable, bool $useKeyAsSecondParameter = false, ...$arguments): self
    {
        $useArguments = \func_num_args() > 2;

        return static::create(
            function () use ($useArguments, $callable, $useKeyAsSecondParameter, $arguments) {
                foreach ($this->getGenerator() as $key => $value) {
                    if ($useArguments) {
                        if ($useKeyAsSecondParameter) {
                            yield $key => $callable($value, $key, ...$arguments);
                        } else {
                            yield $key => $callable($value, ...$arguments);
                        }
                    } else {
                        /** @noinspection NestedPositiveIfStatementsInspection */
                        if ($useKeyAsSecondParameter) {
                            yield $key => $callable($value, $key);
                        } else {
                            yield $key => $callable($value);
                        }
                    }
                }
            },
            $this->iteratorClass,
            false
        );
    }
358159
public function loadArguments($data, callable $callable, Context $context): array
    {
        if (is_object($data) && $data instanceof \stdClass) {
            $data = get_object_vars($data);
        }

        if (!is_array($data)) {
            throw new InvalidDataException('Argument data must array or stdClass');
        }

        $metadata = $this->callableMetadataProvider->getCallableMetadata($callable);

        $args = [];
        $paramPos = 0;
        $argPos = 0;
        while ($paramPos < count($metadata->parameters)) {
            $param = $metadata->parameters[$paramPos];
            $mangledName = $this->nameMangler->mangle($param->name);

            $key = null;
            if (array_key_exists($argPos, $data)) {
                $key = $argPos;
            } elseif (array_key_exists($mangledName, $data)) {
                $key = $mangledName;
            }

            if ($key !== null) {
                $context->pushPath('$' . $key);
                try {
                    $args[] = $this->loader->load($data[$key], $param->type, $context);
                } finally {
                    unset($data[$key]);
                    $context->popPath();
                }
            } elseif ($param->optional) {
                if ($param->variadic) {
                    break;
                }
                $args[] = $param->defaultValue;
            } else {
                throw new InvalidDataException("Required argument $param->name missing");
            }

            $argPos++;
            if (!$param->variadic) {
                $paramPos++;
            }
        }

        if (!empty($data) && $this->throwOnUnknownArgument) {
            throw new InvalidDataException(
                'Some arguments could not be matched: ' . implode(', ', array_keys($data))
            );
        }

        return $args;
    }
946414
private function getDependencies(array $args, array &$arguments)
    {
        $objects = [];
        foreach ($arguments as $k => $v) {
            if (is_object($v)) {
                $objects[$k] = $v;
            }
        }

        $unShift = [];
        $args    = array_reverse($args);

        foreach ($args as $v) {
            $hasDefault = is_array($v);
            $dependency = $hasDefault ? $v[0] : $v;

            if ($objects) {
                $find = false;
                foreach ($objects as $k => $ins) {
                    if (! $ins instanceof $dependency) {
                        continue;
                    }

                    array_unshift($unShift, $ins);
                    unset($arguments[$k], $objects[$k]);

                    $find = true;
                    break;
                }

                if ($find) {
                    continue;
                }
            }

            $alias = $this->getDependencyAlias($dependency);
            if (! $alias) {
                if ($hasDefault) {
                    array_unshift($unShift, null);

                    continue;
                }

                throw new ContainerException("Unresolvable dependency resolving [{$dependency}]");
            }

            array_unshift($unShift, $this->get($alias));
        }
        unset($instance, $objects);

        $arguments = array_merge($unShift, $arguments);
        unset($unShift);
    }
269268
public static function run( Callable $callable ) {

		try {

			// catch fatal errors
			register_shutdown_function(['\\yolk\\exceptions\\Handler', 'checkFatal']);

			// use our error handler
			$error_handler = set_error_handler(static::$error_handler);

			$args = func_get_args();
			array_shift($args);

			$result = call_user_func_array($callable, $args);

			// restore the original error handler
			// if $error_handler is null then passing it to set_error_handler() will fail on PHP < v5.5
			// so we create an empty error handler thereby causing PHP to run it's own handler.
			set_error_handler($error_handler ?: function() { return false; });

			return $result;

		}
		catch( \Exception $e ) {
			static::exception($e);
		}

	}
1073567
public function resolve($callable)
    {
        if (is_string($callable) && strpos($callable, '::') !== false) {
            $callable = explode('::', $callable, 2);
        }

        $callable = $this->resolveFromContainer($callable);

        if (! is_callable($callable)) {
            throw NotCallableException::fromInvalidCallable($callable, true);
        }

        return $callable;
    }
328500
public function getParameters(\ReflectionFunctionAbstract $reflection, array $args = [])
    {
        $dependencies = $reflection->getParameters();
        $parameters = [];

        foreach ($dependencies as $parameter) {
            $parameters[] = $this->getParameter($parameter, $args);
        }

        return $parameters;
    }