Resolve if callable is class method

@param $callable
@return Invokable
518955
public static function ofClassMethod($callable)
    {
        // parse class::method to [class, method]
        if(is_string($callable) and strpos($callable, '::') !== false) {
            $callable = explode('::', $callable);
        }

        // resolve [class, method]
        if(is_array($callable) and count($callable) === 2) {
            $reflector = new \ReflectionMethod($callable[0], $callable[1]);
            if($reflector->isPublic() and !$reflector->isStatic() and !$reflector->isAbstract()) {
                $annotations = array_merge(
                    Annotation::ofClass($callable[0]),
                    Annotation::ofMethod($callable[0], $callable[1])
                );
                return new Invokable($callable, Invokable::CLASS_METHOD, $annotations, $reflector);
            }
        }
    }
701156
private function checkCallable()
    {
        if (is_null($this->callable) || !is_callable($this->callable)) {
            $this->callable = function ($data) {
                $name = $this->name;

                if (is_array($data) && array_key_exists($name, $data)) {
                    return $data[$name];
                }

                if (is_object($data) && property_exists($data, $name)) {
                    return $data->$name;
                }

                if (is_object($data) && method_exists($data, $name)) {
                    return $data->$name();
                }

                return "";
            };
        }
    }
568339
public function resolve($candidate): callable
    {
        if ($resolver = $this->invoker->getCallableResolver()) {
            /** @noinspection PhpUnhandledExceptionInspection */
            return $resolver->resolve($candidate);
        }
        fn\isCallable($candidate) || fn\fail('argument $candidate is not callable');
        return $candidate;
    }
762743
private function _method($name, callable $callable)
    {
        $lastPattern = array_pop($this->_patterns);
        if ($lastPattern) {
            $methods = $lastPattern[6];//路由方法
            $methods[$name] = $callable;
            $lastPattern[6] = $methods;
            $this->_patterns[] = $lastPattern;
        }
        return $this;
    }
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;
    }
167151
public function match($callable)
    {
        $this->remote = lego_register(
            AutoCompleteMatchHandler::class,
            $callable,
            md5(__CLASS__ . $this->name())
        )->remote();

        return $this;
    }
525625
public function register(callable $callable)
    {
        $this->groups[$this->group] = $this->options;

        $callable($this);

        array_pop($this->groups);

        return $this;
    }
399679
protected function isWildCallable($callable, $replaceWith = false)
    {
        $isWild = false;

        if (is_string($callable) && strpos($callable, '*') !== false) {
            $isWild = $replaceWith ? str_replace('*', $replaceWith, $callable) : true;
        }

        if (is_array($callable)) {
            if (is_string($callable[0]) && strpos($callable[0], '*') !== false) {
                if ($replaceWith) {
                    $isWild = $callable;
                    $isWild[0] = str_replace('*', $replaceWith, $callable[0]);
                }
                else {
                    $isWild = true;
                }
            }

            if (!empty($callable[1]) && strpos($callable[1], '*') !== false) {
                if ($replaceWith) {
                    $isWild = $isWild ?: $callable;
                    $isWild[1] = str_replace('*', $replaceWith, $callable[1]);
                }
                else {
                    $isWild = true;
                }
            }
        }

        return $isWild;
    }
622941
public static function getKey($callable)
    {
        /** @var string|null $class */
        $class = null;
        /** @var string|null $method */
        $method = null;

        if (is_string($callable)) {
            $method = $callable; // works for 'Cls::method' case as well
        } elseif (is_array($callable)) {
            $class = is_object($callable[0]) ? get_class($callable[0]) : $callable[0];
            $method = $callable[1];
        } elseif (is_object($callable)) {
            if ($callable instanceof \ReflectionFunctionAbstract) {
                if ($callable->isClosure()) {
                    return null;
                }

                $class = $callable instanceof \ReflectionMethod ? $callable->class : null;
                $method = $callable->name;
            } else {
                if ($callable instanceof \Closure) {
                    return null;
                }

                $class = get_class($callable);
                $method = '__invoke';
            }
        }

        return strtolower(($class ? $class . '::' : '') . $method);
    }
1062278
public function find($callable = null)
    {
        /** @var Cursor $cursor */
        $cursor = new Cursor($this, array(
            'expressionClass'   => $this->definition->getExpressionClass(),
            'batchSize'         => $this->definition->getOption('batchSize'),
            'clientTimeout'     => $this->definition->getOption('cursorClientTimeout'),
            'serverTimeout'     => $this->definition->getOption('cursorServerTimeout'),
        ));

        if (is_callable($callable)) {
            $callable($cursor->getExpression());
        }

        return $cursor;
    }
180798
public function call(callable $callable, array $parameters = [])
	{
		if(is_array($callable))
		{
			$reflection = new ReflectionMethod($callable[0], $callable[1]);
		}
		else
		{
			$reflection = new ReflectionFunction($callable);
		}

		return $callable(...$this->resolveParameters($reflection->getParameters(), $parameters));
	}
182688
public function getCallable(?ContainerInterface $container = null) : callable
    {
        $callable = $this->handler;

        if (is_string($callable) && strpos($callable, '::') !== false) {
            $callable = explode('::', $callable);
        }

        if (is_array($callable) && isset($callable[0]) && is_object($callable[0])) {
            $callable = [$callable[0], $callable[1]];
        }

        if (is_array($callable) && isset($callable[0]) && is_string($callable[0])) {
            $callable = [$this->resolveClass($container, $callable[0]), $callable[1]];
        }

        if (is_string($callable) && method_exists($callable, '__invoke')) {
            $callable = $this->resolveClass($container, $callable);
        }

        if (! is_callable($callable)) {
            throw new InvalidArgumentException('Could not resolve a callable for this route');
        }

        return $callable;
    }
827158
public function invoke(Callable $callable, array $args = [])
    {
        // object/class method
        if (is_string($callable) && false !== strpos($callable, '::')) {
            $callable = explode('::', $callable);
        }
        if (is_array($callable)) {
            $reflection = new \ReflectionMethod($callable[0], $callable[1]);
        }

        // closures, functions and any other callable
        if (!isset($reflection)) {
            $reflection = new \ReflectionFunction($callable);
        }

        // inject arguments
        $arguments = $this->inject($reflection, $args);
        return $callable(...$arguments);
    }
670118
public function any(string $pattern, $callable): MethodsInterface
    {
        // Set new route with all methods
        $this->set(self::METHODS, [$pattern, $callable]);

        return $this;
    }
1362080
public function remove_callable($class)
	{
		if (($key = array_search($class, $this->callables, true)))
		{
			unset($this->callables[$key]);
		}

		return $this;
	}
1175910
public function _and(callable $callable = null)
    {
        $history = $this->whereNeedAddAndOrOr;
        $this->whereNeedAddAndOrOr = 1;

        if (is_callable($callable)) {
            $history === 0 && $this->whereNeedAddAndOrOr = 0;
            $this->lBrackets();
            call_user_func($callable, $this);
            $this->rBrackets();
        }

        return $this;
    }
562078
protected static function cacheId($callable)
    {

        if (is_array($callable)) {
            $class = is_string($callable[0]) ? $callable[0] : get_class($callable[0]);
            return "$class::" . $callable[1];
        }

        if (is_string($callable)) {
            return $callable;
        }

        if (!$callable instanceof \Closure) {
            return get_class($callable);
        }

        $r = new ReflectionFunction($callable);
        return 'Closure:' . $r->getFileName() . ':' . $r->getStartLine() . ':' . $r->getEndLine();

    }