跳转到内容

调度组件


概览

The Phalcon\Mvc\Dispatcher是一个负责在MVC应用程序中实例化控制器并执行所需操作的组件。调度是指接收请求对象,从中提取模块名称、控制器名称、动作名称和可选参数,然后实例化控制器并调用该控制器的动作。

<?php

use Phalcon\Di\Di;
use Phalcon\Mvc\Dispatcher;

$container  = new Di();
$dispatcher = new Dispatcher();

$dispatcher->setDI($container);

$dispatcher->setControllerName("posts");
$dispatcher->setActionName("index");
$dispatcher->setParams([]);

$controller = $dispatcher->dispatch();

方法

public function callActionMethod(
    mixed $handler, 
    string $actionMethod, 
    array $params = []
)
使用处理程序和参数调用一个动作方法

public function dispatch(): object | bool
通过调用适当的控制器动作(包括任何路由数据或注入的参数)来处理路由器的结果。返回已调度的处理程序类(对于MVC调度是Controller,对于CLI调度是Task),或者false如果发生异常并且操作被异常处理器中的返回值停止false。如果在调度过程中发生了未被捕获或未处理的异常,则抛出异常。

public function forward(
    array $forward
): void
将执行流程转发到另一个控制器/动作。

<?php

use Phalcon\Events\Event;
use Phalcon\Mvc\Dispatcher;
use App\Back\Bootstrap as Back;
use App\Front\Bootstrap as Front;

$modules = [
    "frontend" => [
        "className" => Front::class,
        "path"      => __DIR__ . "/app/Modules/Front/Bootstrap.php",
        "metadata"  => [
            "controllersNamespace" => "App\Front\Controllers",
        ],
    ],
    "backend" => [
        "className" => Back::class,
        "path"      => __DIR__ . "/app/Modules/Back/Bootstrap.php",
        "metadata"  => [
            "controllersNamespace" => "App\Back\Controllers",
        ],
    ],
];

$application->registerModules($modules);

$eventsManager = $container->getShared("eventsManager");

$eventsManager->attach(
    "dispatch:beforeForward",
    function (
        Event $event, 
        Dispatcher $dispatcher, 
        array $forward
    ) use ($modules) {
        $metadata = $modules[$forward["module"]]["metadata"];

        $dispatcher->setModuleName(
            $forward["module"]
        );

        $dispatcher->setNamespaceName(
            $metadata["controllersNamespace"]
        );
    }
);

// Forward
$this->dispatcher->forward(
    [
        "module"     => "backend",
        "controller" => "posts",
        "action"     => "index",
    ]
);

public function getActionName(): string
获取最后分发的动作名称

public function getActionSuffix(): string
获取默认的动作后缀

public function getActiveController(): ControllerInterface
返回调度器中的活动控制器

public function getActiveMethod(): string
返回调度器中将要/已执行的当前方法

public function getBoundModels(): array
返回绑定实例中的绑定模型

<?php

use Phalcon\Mvc\Dispatcher;

/**
 * @property Dispatcher $dispatcher
 */
class InvoicesController extends Controller
{
    public function viewAction(Invoices $invoice)
    {
        $boundModels = $this
            ->dispatcher
            ->getBoundModels()
        ;
    }
}

public function getControllerClass(): string
可能用于分发请求的控制器类名

public function getControllerName(): string
获取最后调度的控制器名称

public function getDefaultNamespace(): string
返回默认的命名空间

public function getHandlerClass(): string
可能定位到用于分发请求的类名

public function getHandlerSuffix(): string
获取默认的处理器后缀

public function getLastController(): ControllerInterface
返回最后分发的控制器

public function getModelBinder(): BinderInterface | null
获取模型绑定器

public function getModuleName(): string
获取控制器类所在的模块

public function getNamespaceName(): string
获取将被添加到当前处理器名称前的命名空间

public function getParam(
    mixed $param, 
    string | array $filters = null, 
    mixed $defaultValue = null
): mixed
按参数名称或数字索引获取参数

public function getParams(): array
获取动作参数

public function getPreviousActionName(): string
获取上一次调度的动作名称

public function getPreviousControllerName(): string
获取上一次调度的控制器名称

public function getPreviousNamespaceName(): string
获取上一次调度的命名空间名称

public function getReturnedValue(): mixed
返回最新分发动作返回的值

public function hasParam(
    mixed $param
): bool
检查参数是否存在

public function isFinished(): bool
检查调度循环是否完成或还有待调度的其他控制器/任务

public function setActionName(
    string $actionName
): void
设置将要分发的动作名称

public function setActionSuffix(
    string $actionSuffix
): void
设置默认的动作后缀

public function setControllerName(
    string $controllerName
)
设置要调度的控制器名称

public function setControllerSuffix(
    string $controllerSuffix
)
设置默认控制器后缀

public function setDefaultAction(
    string $actionName
): void
设置默认的动作名称

public function setDefaultController(
    string $controllerName
)
设置默认控制器名

public function setDefaultNamespace(
    string $namespaceName
): void
设置默认的命名空间

public function setHandlerSuffix(
    string $handlerSuffix
): void
设置处理器的默认后缀

public function setModelBinder(
    BinderInterface $modelBinder, 
    mixed $cache = null
): DispatcherInterface
在分发期间启用模型绑定

$container->set(
    'dispatcher',
    function() {
        $dispatcher = new Dispatcher();

        $dispatcher->setModelBinder(
            new Binder(),
            'cache'
        );

        return $dispatcher;
    }
);

public function setModuleName(
    string $moduleName
): void
设置控制器所在的模块(仅用于信息提供)

public function setNamespaceName(
    string $namespaceName
): void
设置控制器类所在的命名空间

public function setParam(
    mixed $param, 
    mixed $value
): void
根据名称或数值索引设置参数

public function setParams(
    array $params
): void
设置将要分发的动作参数

public function setReturnedValue(
    mixed $value
): void
手动设置动作返回的最新值

public function wasForwarded(): bool
检查当前执行的动作是否由另一个动作转发

分发循环

这是一个与MVC流程本身特别是控制器部分密切相关的关键过程。工作发生在控制器调度器内。控制器文件被读取、加载和实例化。接着执行所需的动作。如果某个动作将流程转发到其他控制器/动作,控制器调度器会重新开始。为了更好地说明这一点,以下示例近似展示了内部进行的过程:Phalcon\Mvc\Dispatcher组件定义的。

<?php

$finished = false;

while (true !== $finished) {
    $finished = true;

    $controllerClass = $controllerName . 'Controller';
    $controller      = new $controllerClass();

    call_user_func_array(
        [
            $controller,
            $actionName . 'Action',
        ],
        $params
    );

    $finished = true;
}
在上面的代码中,我们计算控制器名称,实例化它,并调用相关动作。之后,我们结束循环。这个例子非常简化,缺乏验证、过滤和额外的检查,但它演示了调度器内的正常操作流程。

转发

调度循环允许你将执行流转发到另一个控制器/动作。这在检查用户是否有权限访问某些区域时非常有用,如果没有权限可以转发到其他控制器和动作,从而允许你重用代码。

<?php

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\Dispatcher;

/**
 * @property Dispatcher $dispatcher
 */
class InvoicesController extends Controller
{
    public function saveAction($year, $postTitle)
    {
        // ... 

        $this->dispatcher->forward(
            [
                'controller' => 'invoices',
                'action'     => 'list',
            ]
        );
    }
}

注意

请注意,forward的行为不同于HTTP重定向。尽管它们会产生相同的结果,forward不会重新加载当前页面,而HTTP重定向需要两次请求才能完成整个过程。

示例:

<?php

$this->dispatcher->forward(
    [
        'action' => 'search',
    ]
);
将流程转发到当前控制器中的另一动作

<?php

$this->dispatcher->forward(
    [
        'action' => 'search',
        'params' => [1, 2, 3],
    ]
);
将流程转发到当前控制器中的另一动作,并传递参数

A forward动作接受以下参数:

参数 描述
controller 要转发的有效控制器名称。
action 要转发的有效动作名称。
params 动作的参数数组。
namespace 控制器所属的有效命名空间名称。

参数

准备

通过使用Phalcon\Mvc\Dispatcher提供的事件或钩子点,你可以轻松调整你的应用程序以接受适合你的应用的任何URL模式。当你升级应用程序并希望转换一些遗留的URL时,这尤其有用。例如,你可能希望你的URL如下所示:

https://domain.com/controller/key1/value1/key2/value

因为参数是按照它们在URL中定义的顺序传给动作的,所以你可以将它们转换为你期望的模式:

<?php

use Phalcon\Dispatcher;
use Phalcon\Mvc\Dispatcher as MvcDispatcher;
use Phalcon\Events\Event;
use Phalcon\Events\Manager;

$container->set(
    'dispatcher',
    function () {
        $eventsManager = new Manager();

        $eventsManager->attach(
            'dispatch:beforeDispatchLoop',
            function (Event $event, $dispatcher) {
                $params    = $dispatcher->getParams();
                $keyParams = [];

                foreach ($params as $index => $value) {
                    if ($index & 1) {
                        $key = $params[$index - 1];

                        $keyParams[$key] = $value;
                    }
                }

                $dispatcher->setParams($keyParams);
            }
        );

        $dispatcher = new MvcDispatcher();
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
);

如果期望的模式是:

https://example.com/controller/key1:value1/key2:value

你可以使用以下代码:

<?php

use Phalcon\Dispatcher;
use Phalcon\Events\Event;
use Phalcon\Events\Manager;
use Phalcon\Mvc\Dispatcher as MvcDispatcher;

$container->set(
    'dispatcher',
    function () {
        $eventsManager = new Manager();

        $eventsManager->attach(
            'dispatch:beforeDispatchLoop',
            function (Event $event, $dispatcher) {
                $params    = $dispatcher->getParams();
                $keyParams = [];

                foreach ($params as $param) {
                    $parts = explode(':', $param);
                    $key   = $parts[0];
                    $value = $parts[1];

                    $keyParams[$key] = $value;
                }

                $dispatcher->setParams($keyParams);
            }
        );

        $dispatcher = new MvcDispatcher();
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
);

获取

当路由提供命名参数时,你可以在控制器、视图或任何继承自Phalcon\Di\Injectable

<?php

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\Dispatcher;

/**
 * @property Dispatcher $dispatcher
 */
class InvoicesController extends Controller
{
    public function viewAction()
    {
        $invoiceId = $this
            ->dispatcher
            ->getParam('invoiceId', 'int')
        ;
        $filter = $this
            ->dispatcher
            ->getParam('filter', 'string')
        ;

        // ...
    }
}
在上述示例中,我们获取invoiceId作为传入的第一个参数,并自动将其清理为integer类型。第二个参数是filter,它被清理为string

动作

类型。你还可以为动作定义任意的模式before调度循环被调用时。

驼峰命名

如果原始URL是

https://example.com/admin/invoices/show-unpaid

例如你想要驼峰化show-unpaidShowUnpaidbeforeDispatchLoop可以用来实现这一点。

<?php

use Phalcon\Mvc\Dispatcher as MvcDispatcher;
use Phalcon\Events\Event;
use Phalcon\Events\Manager as Manager;

$helper = $container->getShared('helper');
$container->set(
    'dispatcher',
    function () use ($helper) {
        $eventsManager = new Manager();

        $eventsManager->attach(
            'dispatch:beforeDispatchLoop',
            function (Event $event, $dispatcher) {
                $dispatcher->setActionName(
                    $helper->camelize(
                        $dispatcher->getActionName()
                    )
                );
            }
        );

        $dispatcher = new MvcDispatcher();
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
);

过滤文件扩展名

如果原始URL始终包含一个.php扩展名:

https://example.com/admin/invoices/show-unpaid.php
https://example.com/admin/invoices/index.php

你可以在调度控制器/动作组合之前将其移除:

<?php

use Phalcon\Mvc\Dispatcher as MvcDispatcher;
use Phalcon\Events\Event;
use Phalcon\Events\Manager;

$container->set(
    'dispatcher',
    function () {
        $eventsManager = new Manager();

        $eventsManager->attach(
            'dispatch:beforeDispatchLoop',
            function (Event $event, $dispatcher) {
                $action = $dispatcher->getActionName();
                $action = preg_replace('/\.php$/', '', $action);

                $dispatcher->setActionName($action);
            }
        );

        $dispatcher = new MvcDispatcher();
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
);

注意

上述代码可以直接使用或根据需要调整,有助于遗留URL的转换或其他需要操作动作名称的使用场景。

模型注入

有时候你可能希望将那些与URL中传递的参数匹配的模型实例自动注入。

我们的控制器是:

<?php

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\View;

/**
 * @property View $view
 */
class InvoicesController extends Controller
{
    public function viewAction(Invoices $invoice)
    {
        $this->view->invoice = $invoice;
    }
}
The viewAction接收一个模型实例Invoices。如果你尝试不经过任何检查和操作就执行此方法,调用将会失败。但是你可以在调度循环之前检查传入的参数,并相应地操作这些参数。

<?php

use \Exception;
use Phalcon\Events\Event;
use Phalcon\Events\Manager;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Dispatcher as MvcDispatcher;
use \ReflectionMethod;

$container->set(
    'dispatcher',
    function () {
        $eventsManager = new Manager();

        $eventsManager->attach(
            'dispatch:beforeDispatchLoop',
            function (Event $event, $dispatcher) {
                $controllerName = $dispatcher->getControllerClass();
                $actionName     = $dispatcher->getActiveMethod();

                try {
                    $reflection = new ReflectionMethod(
                        $controllerName, 
                        $actionName
                    );
                    $parameters = $reflection->getParameters();

                    foreach ($parameters as $parameter) {
                        $className = $parameter->getClass()->name;

                        if (is_subclass_of($className, Model::class)) {
                            $model = $className::findFirstById(
                                $dispatcher->getParams()[0]
                            );

                            $dispatcher->setParams(
                                [
                                    $model,
                                ]
                            );
                        }
                    }
                } catch (Exception $e) {
                }
            }
        );

        $dispatcher = new MvcDispatcher();
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
);
在上面的示例中,我们从调度器中获取控制器类和活动方法。遍历参数时,我们使用反射来检查将要执行的方法。我们计算模型名称,并检查参数是否期望的是模型名称。如果是,我们就通过传递找到的模型覆盖该参数。如果抛出了异常,我们可以相应地处理它,例如,如果类或动作不存在或者记录未找到。

上面的示例已被简化。您可以根据需要进行调整,并在执行之前将任何类型的依赖项或模型注入到操作中。

调度器还提供了一个选项,可通过使用Phalcon\Mvc\Model\Binder对象中的相关方法手动

<?php

use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\Model\Binder;

$dispatcher = new Dispatcher();

$dispatcher->setModelBinder(
    new Binder()
);

return $dispatcher;

注意

The Phalcon\Mvc\Model\Binder该组件在内部使用了PHP的反射API,会消耗额外的处理周期。因此,它有能力使用一个cache实例或者缓存服务名称。要使用此功能,您可以在setModelBinder()方法中将缓存服务名称或实例作为第二个参数传递,或者直接在Binder构造函数中传递缓存实例。

此外,通过在控制器中使用Phalcon\Mvc\Model\Binder\BindableInterface接口,您可以在基类控制器中定义模型绑定。

在下面的示例中,我们有一个基类控制器CrudControllerInvoicesController继承自。

<?php

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\View;

/**
 * @property View $view
 */
class CrudController extends Controller
{
    public function viewAction(Model $model)
    {
        $this->view->model = $model;
    }
}

InvoicesController我们将定义该控制器关联的模型。这可以通过实现Phalcon\Mvc\Model\Binder\BindableInterface接口来完成,这样就会使getModelName()方法可用。这个方法用来返回模型名称。它可以返回一个仅包含一个模型名称的字符串,或者返回一个键为参数名的关联数组。

<?php

use Phalcon\Mvc\Model\Binder\BindableInterface;

class InvoicesController extends CrudController implements BindableInterface
{
    public function getModelName()
    {
        return Invoices::class;
    }
}

通过声明与InvoicesController绑定器可以检查控制器中的getModelName()方法,然后将定义好的模型传入父类view动作。

如果您的项目结构不使用任何基类控制器,当然您仍然可以直接将模型绑定到控制器操作中:

<?php

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\View;

/**
 * @property View $view
 */
class InvoicesController extends Controller
{
    public function showAction(Invoices $invoice)
    {
        $this->view->invoice = $invoice;
    }
}

注意

目前,绑定器只会使用模型的主键来执行一个findFirst()。上面的示例路由可能是这样的/posts/show/{1}

未找到(404)

如果已经定义了事件管理器,则可以使用它拦截找不到控制器/操作对时抛出的异常。

<?php

use Exception;
use Phalcon\Dispatcher;
use Phalcon\Mvc\Dispatcher as MvcDispatcher;
use Phalcon\Events\Event;
use Phalcon\Events\Manager;
use Phalcon\Mvc\Dispatcher\Exception as DispatchException;

$container->setShared(
    'dispatcher',
    function () {
        $eventsManager = new Manager();

        $eventsManager->attach(
            'dispatch:beforeException',
            function (
                Event $event, 
                $dispatcher, 
                Exception $exception
            ) {
                // 404
                if ($exception instanceof DispatchException) {
                    $dispatcher->forward(
                        [
                            'controller' => 'index',
                            'action'     => 'fourOhFour',
                        ]
                    );

                    return false;
                }
            }
        );

        $dispatcher = new MvcDispatcher();
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
);

或者使用替代语法检查异常。

<?php

use Exception;
use Phalcon\Dispatcher\Exception as DispatcherException;
use Phalcon\Mvc\Dispatcher as MvcDispatcher;
use Phalcon\Events\Event;
use Phalcon\Events\Manager;

$container->setShared(
    'dispatcher',
    function () {
        $eventsManager = new Manager();

        $eventsManager->attach(
            'dispatch:beforeException',
            function (
                Event $event, 
                $dispatcher, 
                Exception $exception
            ) {
                switch ($exception->getCode()) {
                    case DispatcherException::EXCEPTION_HANDLER_NOT_FOUND:
                    case DispatcherException::EXCEPTION_ACTION_NOT_FOUND:
                        // 404
                        $dispatcher->forward(
                            [
                                'controller' => 'index',
                                'action'     => 'fourOhFour',
                            ]
                        );

                        return false;
                }
            }
        );

        $dispatcher = new MvcDispatcher();
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
);

我们可以将此方法移至插件类中:

<?php

use Exception;
use Phalcon\Events\Event;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\Dispatcher\Exception as DispatchException;

class ExceptionsPlugin
{
    public function beforeException(
        Event $event, 
        Dispatcher $dispatcher, 
        Exception $exception
    ) {
        $action = 'fiveOhThree';

        if ($exception instanceof DispatchException) {
            $action = 'fourOhFour';
        }

        $dispatcher->forward(
            [
                'controller' => 'index',
                'action'     => $action,
            ]
        );

        return false;
    }
}

注意

只有由调度器产生的异常和在执行操作时产生的异常才会通知beforeException事件。在监听器或控制器事件中产生的异常会被重定向到最近的try/catch块中。

事件

Phalcon\Mvc\Dispatcher能够发送事件给管理器如果其存在的话。事件使用类型dispatch来触发。一些事件在返回布尔值时false可以停止当前操作。支持以下事件:

事件名称 触发时机 可以停止
afterBinding 在模型绑定后但在执行路由之前。
afterDispatch 在执行完控制器/操作方法之后。
afterDispatchLoop 在退出调度循环后
afterExecuteRoute 在执行完控制器/操作方法之后。
afterInitialize 允许在整个请求中初始化控制器
beforeDispatch 在进入调度循环之后。调度器只知道路由器传递的信息。
beforeDispatchLoop 在进入调度循环之前。调度器只知道路由器传递的信息。
beforeException 在调度器抛出任何异常之前
beforeExecuteRoute 在执行控制器/操作方法之前。调度器已经初始化了控制器,并知道该操作是否存在。
beforeForward 在转发到控制器/操作方法之前。(MVC调度器)
beforeNotFoundAction 当控制器中找不到操作时

The INVO示例应用程序展示了您可以如何利用调度事件并使用Acl

下面的示例演示了如何将监听器附加到此组件上:

<?php

use Phalcon\Mvc\Dispatcher as MvcDispatcher;
use Phalcon\Events\Event;
use Phalcon\Events\Manager;

$container->set(
    'dispatcher',
    function () {
        $eventsManager = new Manager();

        $eventsManager->attach(
            'dispatch',
            function (Event $event, $dispatcher) {
                // ...
            }
        );

        $dispatcher = new MvcDispatcher();
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    },
    true
);

初始化后的控制器自动充当调度事件的监听器,因此您可以将方法实现作为回调:

<?php

use Phalcon\Mvc\Controller;
use Phalcon\Mvc\Dispatcher;

class InvoicesController extends Controller
{
    public function beforeExecuteRoute(
        Dispatcher $dispatcher
    ) {
        // ...
    }

    public function afterExecuteRoute(
        Dispatcher $dispatcher
    ) {
        // ...
    }
}

注意

事件监听器上的方法接受一个Phalcon\Events\Event对象作为第一个参数 - 控制器中的方法则没有。

事件管理器

您可以使用dispatcher::beforeForward事件以便更轻松地更改模块和执行重定向。

<?php

use App\Back\Bootstrap;
use Phalcon\Di\Di;
use Phalcon\Events\Manager;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Events\Event;

$container = new Di();

$modules = [
    'backend' => [
        'className' => Bootstrap::class,
        'path'      => '/app/Modules/Back/Bootstrap.php',
        'metadata'  => [
            'controllersNamespace' => 'App\Back\Controllers',
        ],
    ],
];

$manager = new Manager();
$manager->attach(
    'dispatch:beforeForward',
    function (
        Event $event, 
        Dispatcher $dispatcher, 
        array $forward
    ) use ($modules) {
        $moduleName = $forward['module'];
        $metadata   = $modules[$moduleName]['metadata'];

        $dispatcher->setModuleName($moduleName);
        $dispatcher->setNamespaceName(
            $metadata['controllersNamespace']
        );
    }
);

$dispatcher = new Dispatcher();
$dispatcher->setDI($container);
dispatcher->setManager($manager);
$container->set('dispatcher', $dispatcher);

$dispatcher->forward(
    [
        'module'     => 'backend',
        'controller' => 'invoices',
        'action'     => 'index',
    ]
);

echo $dispatcher->getModuleName();

自定义

The Phalcon\Mvc\DispatcherInterface接口必须被实现以创建自己的调度器。

<?php

namespace MyApp\Mvc

use Phalcon\Mvc\DispatcherInterface;

class MyDispatcher implements DispatcherInterface
{
    /**
     * Dispatches a handle action taking into account the routing parameters
     */
    public function dispatch(): object | bool;

    /**
     * Forwards the execution flow to another controller/action
     */
    public function forward(array $forward): void;

    /**
     * Gets last dispatched action name
     */
    public function getActionName(): string;

    /**
     * Gets the default action suffix
     */
    public function getActionSuffix(): string;

    /**
     * Returns the active controller in the dispatcher
     */
    public function getActiveController(): ControllerInterface;

    /**
     * Gets last dispatched controller name
     */
    public function getControllerName(): string;

    /**
     * Gets the default handler suffix
     */
    public function getHandlerSuffix(): string;

    /**
     * Returns the latest dispatched controller
     */
    public function getLastController(): ControllerInterface;

    /**
     * Gets a param by its name or numeric index
     *
     * @param string|array filters
     */
    public function getParam($param, $filters = null);

    /**
     * Gets action params
     */
    public function getParams(): array;

    /**
     * Returns value returned by the latest dispatched action
     */
    public function getReturnedValue();

    /**
     * Check if a param exists
     */
    public function hasParam($param): bool;

    /**
     * Checks if the dispatch loop is finished or has more pending
     * controllers/tasks to dispatch
     */
    public function isFinished(): bool;

    /**
     * Sets the action name to be dispatched
     */
    public function setActionName(string $actionName): void;

    /**
     * Sets the default action suffix
     */
    public function setActionSuffix(string $actionSuffix): void;

    /**
     * Sets the default controller suffix
     */
    public function setControllerSuffix(string $controllerSuffix);

    /**
     * Sets the controller name to be dispatched
     */
    public function setControllerName(string $controllerName);

    /**
     * Sets the default action name
     */
    public function setDefaultAction(string $actionName): void;

    /**
     * Sets the default controller name
     */
    public function setDefaultController(string $controllerName);

    /**
     * Sets the default namespace
     */
    public function setDefaultNamespace(string $defaultNamespace): void;

    /**
     * Sets the default suffix for the handler
     */
    public function setHandlerSuffix(string $handlerSuffix): void;

    /**
     * Sets the module name which the application belongs to
     */
    public function setModuleName(string $moduleName): void;

    /**
     * Sets the namespace to which the controller belongs to
     */
    public function setNamespaceName(string $namespaceName): void;

    /**
     * Set a param by its name or numeric index
     *
     * @param  mixed value
     */
    public function setParam($param, $value): void;

    /**
     * Sets action params to be dispatched
     */
    public function setParams(array $params): void;
}