protected function callHandler(string $path, string $method, $handler, array $args = [])
    {
        // is a \Closure or a callable object
        if (\is_object($handler)) {
            return $handler($args);
        }

        //// $handler is string

        // is array ['controller', 'action']
        if (\is_array($handler)) {
            $segments = $handler;
        } elseif (\is_string($handler)) {
            // is function
            if (\strpos($handler, '@') === false && \function_exists($handler)) {
                return $handler($args);
            }

            // e.g `Controllers\Home@index` Or only `Controllers\Home`
            $segments = \explode('@', \trim($handler));
        } else {
            throw new \InvalidArgumentException("Invalid route handler for route '$path'");
        }

        // Instantiation controller
        $controller = new $segments[0]();

        // Already assign action
        if (!empty($segments[1])) {
            $action = $segments[1];

            // use dynamic action
        } elseif ($this->options['dynamicAction'] && ($var = $this->options['dynamicActionVar'])) {
            $action = isset($args[$var]) ? \trim($args[$var], '/') : $this->options['defaultAction'];

            // defined default action
        } elseif (!$action = $this->options['defaultAction']) {
            throw new \RuntimeException("please config the route path [$path] controller action to call");
        }

        $action = RouteHelper::str2Camel($action);
        $actionMethod = $action . $this->options['actionSuffix'];

        // if set the 'actionExecutor', the action handle logic by it.
        if ($executor = $this->options['actionExecutor']) {
            return $controller->$executor($actionMethod, $args);
        }

        // action method is not exist
        if (!\method_exists($controller, $actionMethod)) {
            return $this->handleNotFound($path, $method, true);
        }

        // call controller's action method
        return $controller->$actionMethod($args);
    }