To extract the list of ReflectionParameter instances about the current callable
and cache them for next call.

@param callable $callable

@return \ReflectionParameter[]
@throws \ReflectionException
975105
private function getParametersInOrder(callable $callable): array
    {
        if (null === $this->parametersCache) {
            $this->parametersCache = $this->listParameters($callable);
        }

        return $this->parametersCache;
    }
917658
private function getRefParamsFromCallable(callable $callable, $funcName)
    {
        if (is_string($callable)) {
            $ref       = new ReflectionFunction($callable);
            $refParams = $ref->getParameters();
        } elseif (is_array($callable)) {
            $ref       = new ReflectionMethod($callable[0], $callable[1]);
            $refParams = $ref->getParameters();
        } elseif (is_object($callable)) {
            $ref       = new ReflectionMethod($callable, '__invoke');
            $refParams = $ref->getParameters();
        } else {
            throw new MarkupException(sprintf('type of callable function %s() is not supported', $funcName));
        }

        return $refParams;
    }
316056
public static function share($callable)
    {
        if (!is_object($callable) || !method_exists($callable, '__invoke')) {
            throw new InvalidArgumentException('Callable is not a Closure or invokable object.');
        }
        
        return function ($c) use ($callable) {
            static $object;

            if (null === $object) {
                $object = $callable($c);
            }

            return $object;
        };
    }
788521
public function read($table, callable $callable = null)
    {

        $this->connect($table);
        $read = new Read($this);

        return $callable($read);
    }
1156200
public function argumentsForCallback(callable $callback): array
    {
        $definition = new ReflectionFunction($callback);
        $arguments = [];

        foreach ($definition->getParameters() as $parameter) {
            if ($type = $parameter->getType()) {
                $arguments[] = Phony::emptyValue($type);
            } else {
                $arguments[] = null;
            }
        }

        return $arguments;
    }
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;
    }
518924
private function hashCallable($callable)
    {
        $result = '';
        if (is_string($callable)) {
            $result = $callable;
        } else if (is_array($callable)) {
            $callableEntity = array_shift($callable);
            $result = is_object($callableEntity) ? get_class($callableEntity) : serialize($callableEntity);
            $result .= serialize($callable[0]);
        } else if ($callable instanceof \Closure) {
            $serializer = new Serializer();
            return $serializer->serialize($callable);
        } else if (is_object($callable)) {
            $result = serialize($callable);
        }
        return md5($result);
    }
779374
public static function getReflectionCallable($callable)
    {
        if (is_callable($callable, true)) {
            try {
                if (is_object($callable)) {
                    return new ReflectionFunction($callable);
                }
                if (is_array($callable)) {
                    return new ReflectionMethod($callable[0], $callable[1]);
                }
                if (strpos($callable, '::') === false) {
                    return new ReflectionFunction($callable);
                }
                return new ReflectionMethod($callable);
            } catch (ReflectionException $exception) {
            }
        }
        return false;
    }
915241
private function extractParameters(callable $callable, ChefInterface $chef, array &$workPlan): array
    {
        $values = [];
        foreach ($this->getParametersInOrder($callable) as $name => $parameter) {
            $class = $parameter->getClass();

            if ($class instanceof \ReflectionClass && $class->isInstance($chef)) {
                $values[] = $chef;
                continue;
            }

            if (!empty($this->mapping[$name])) {
                $name = $this->mapping[$name];
            }

            if (isset($workPlan[$name])) {
                $values[] = $workPlan[$name];
                continue;
            }

            if ($class instanceof \ReflectionClass) {
                $automaticValueFound = $this->findInstanceForParameter($class, $workPlan, $values);

                if (true === $automaticValueFound) {
                    continue;
                }
            }

            if (BowlInterface::METHOD_NAME === $name) {
                $values[] = $this->name;
                continue;
            }

            if (!$parameter->isOptional()) {
                throw new \RuntimeException("Missing the parameter {$parameter->getName()} in the WorkPlan");
            }

            $values[] = $parameter->getDefaultValue();
        }

        return $values;
    }
773217
private static function getCallToolArgs($callable, $tool, $operation)
    {
        $className = get_parent_class($callable[0]);
        $methodRef = new \ReflectionMethod($className, $callable[1]);
        $annotations = ToolParser::getInstance()->getData()['class'][$className]['Methods'][$methodRef->name]['Args'] ?? [];
        $args = [];
        foreach($methodRef->getParameters() as $param)
        {
            $annotation = $annotations[$param->name] ?? null;
            if(null === $annotation)
            {
                $value = $param->isOptional() ? $param->getDefaultValue() : null;
            }
            else if(Args::exists($annotation->name))
            {
                $value = static::parseArgValue(Args::get($annotation->name), $annotation);
            }
            else if($annotation->required)
            {
                throw new \InvalidArgumentException(sprintf('tool %s/%s param %s is required', $tool, $operation, $annotation->name));
            }
            else
            {
                $value = $annotation->default;
            }
            $args[] = $value;
        }
        return $args;
    }
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();
    }
1247072
public function each($callable)
    {
        if ($this instanceof Iterator) {

            if (is_string($callable)) {
                foreach ($this as $obj) {
                    if ($obj->$callable() === false) {
                        break;
                    }
                }

                return $this;
            }

            foreach ($this as $obj) {
                if (call_user_func($callable, $obj) === false) {
                    break;
                }
            }

        } else {
            throw $this->exception('Calling each() on non-iterative object');
        }

        return $this;
    }
1117271
private function listParameters(callable $callable): array
    {
        $parameters = [];
        foreach ($this->getReflection($callable)->getParameters() as $parameter) {
            $parameters[$parameter->getName()] = $parameter;
        }

        return $parameters;
    }
891145
public function map(callable $callable)
    {
        $keys = array_keys($this->items);
        $results = array_map($callable, $this->items, $keys);

        return new self($results);
    }
517838
public static function getArity($callable)
    {
        if (is_object($callable)) {
            foreach (['__invoke', 'handle'] as $method) {
                if (! method_exists($callable, $method)) {
                    continue;
                }

                $r = new ReflectionMethod($callable, $method);
                return $r->getNumberOfRequiredParameters();
            }
            return 0;
        }

        if (! is_callable($callable)) {
            return 0;
        }

        $r = new ReflectionFunction($callable);
        return $r->getNumberOfRequiredParameters();
    }
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);
    }
1120854
static function makeReflectFromCallable(callable $callable)
    {
        if ( $callable instanceof ipInvokableCallback )
            $callable = $callable->getCallable();

        if ( is_array($callable) )
            // [className_orObject, 'method_name']
            $reflection = new \ReflectionMethod($callable[0], $callable[1]);

        if ( is_string($callable) ) {
            if ( strpos($callable, '::') )
                // 'classname::method'
                $reflection = new \ReflectionMethod($callable);
            else
                // 'function_name'
                $reflection = new \ReflectionFunction($callable);
        }

        if ( method_exists($callable, '__invoke') ) {
            // Closure and Invokable
            if ($callable instanceof \Closure)
                $reflection = new \ReflectionFunction($callable);
            else
                $reflection = new \ReflectionMethod($callable, '__invoke');
        }

        if (! isset($reflection) )
            throw new \ReflectionException;

        return $reflection;
    }