命令行应用程序¶
概览¶
CLI 是 Command Line Interface(命令行界面)的缩写。CLI 应用程序从命令行或 shell 提示符中执行。CLI 应用程序的一个好处是它们没有视图层(仅可能在屏幕上回显输出),并且可以同时运行多次。一些常见的用途包括定时任务、操作脚本、导入数据脚本、命令工具等。
结构¶
您可以使用Phalcon\Cli\Console
类在 Phalcon 中创建一个 CLI 应用程序。这个类扩展自主要的抽象应用程序类,并使用一个包含Task
脚本所在的目录。Task
脚本是扩展Phalcon\Cli\Task
的类,并包含需要执行的代码。
CLI 应用程序的目录结构可能如下所示:
在上面的例子中,将cli.php
是我们应用程序的入口点,而src/tasks
目录包含处理每个命令的所有任务类。 注意
每个任务文件和类必须以Task
结尾。如果未传递参数,则默认任务是MainTask
,而在任务内要执行的默认方法是main
引导程序¶
正如上面所见,我们 CLI 应用程序的入口点是cli.php
。在该脚本中,我们需要引导我们的应用程序并添加相关的服务、指令等。这类似于我们在 MVC 应用程序中使用的熟悉的index.php
。
<?php
declare(strict_types=1);
use Exception;
use Phalcon\Autoload\Loader;
use Phalcon\Cli\Console;
use Phalcon\Cli\Dispatcher;
use Phalcon\Cli\Console\Exception as PhalconException;
use Phalcon\Di\FactoryDefault\Cli as CliDI;
use Throwable;
$loader = new Loader();
$loader->setNamespaces(
[
'MyApp' => 'src/',
]
);
$loader->register();
$container = new CliDI();
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace('MyApp\Tasks');
$container->setShared('dispatcher', $dispatcher);
$container->setShared('config', function () {
return include 'app/config/config.php';
});
$console = new Console($container);
$arguments = [];
foreach ($argv as $k => $arg) {
if ($k === 1) {
$arguments['task'] = $arg;
} elseif ($k === 2) {
$arguments['action'] = $arg;
} elseif ($k >= 3) {
$arguments['params'][] = $arg;
}
}
try {
$console->handle($arguments);
} catch (PhalconException $e) {
fwrite(STDERR, $e->getMessage() . PHP_EOL);
exit(1);
} catch (Throwable $throwable) {
fwrite(STDERR, $throwable->getMessage() . PHP_EOL);
exit(1);
} catch (Exception $exception) {
fwrite(STDERR, $exception->getMessage() . PHP_EOL);
exit(1);
}
首先,我们需要为我们的 CLI 应用程序创建所有必要的服务。我们将创建一个加载器来自动加载我们的任务、CLI 应用程序、调度器以及 CLI 控制台应用程序。这些是我们创建 CLI 应用程序所需实例化的最少服务。
加载器
创建 Phalcon 自动加载器并将命名空间注册到 src/ 目录。注意
如果您决定在您的composer.json
中使用 Composer 自动加载器,则无需在此应用程序中注册加载器。
依赖注入
我们需要一个依赖注入容器。您可以使用Phalcon\Di\FactoryDefault\Cli
容器,它已经为您注册了服务。或者,您始终可以使用Phalcon\Di
并逐一注册您需要的服务。 分派器
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace('MyApp\Tasks');
$container->setShared('dispatcher', $dispatcher);
Phalcon\Cli\Dispatcher
提供与 MVC 应用程序的主要调度器相同的功能,但它是为 CLI 应用程序量身定制的。如预期的那样,我们实例化调度器对象,设置我们的默认命名空间,然后将其注册到 DI 容器中。 配置
上面的代码片段是可选的,但它将允许您访问已设置的任何配置设置。确保将 include 路径更新为相对于您的cli.php
文件的位置。
应用程序
如上所述,CLI 应用程序由Phalcon\Cli\Console
类处理。在这里我们实例化它并将其传递给 DI 容器。 参数
我们的应用程序需要参数。它们以以下形式出现:
第一个参数与要执行的任务相关。第二个参数是动作,之后跟随我们需要传递的参数。$arguments = [];
foreach ($argv as $k => $arg) {
if ($k === 1) {
$arguments['task'] = $arg;
} elseif ($k === 2) {
$arguments['action'] = $arg;
} elseif ($k >= 3) {
$arguments['params'][] = $arg;
}
}
$argv
接收通过命令行传递的内容,并相应地拆分这些参数以理解需要调用哪个任务和动作以及使用哪些参数。 因此对于以下示例:
我们的应用程序将调用UsersTask
,调用recalculate
动作并传递参数10
. 执行
try {
$console->handle($arguments);
} catch (PhalconException $e) {
fwrite(STDERR, $e->getMessage() . PHP_EOL);
exit(1);
} catch (Throwable $throwable) {
fwrite(STDERR, $throwable->getMessage() . PHP_EOL);
exit(1);
} catch (Exception $exception) {
fwrite(STDERR, $exception->getMessage() . PHP_EOL);
exit(1);
}
handle
使用计算出的参数。CLI 应用程序将进行必要的路由并分发请求的任务和动作。如果抛出异常,则会被catch
语句捕获,并根据相应的错误显示在屏幕上。 异常¶
在Phalcon\Cli\Console
组件中抛出的任何异常类型为Phalcon\Cli\Console\Exception
中抛出的任何异常都可以让您专门捕获该异常。
任务¶
任务相当于 MVC 应用程序中的控制器。任何 CLI 应用程序都需要至少一个名为MainTask
和mainAction
的任务。任何定义的任务都需要有一个mainAction
,如果没有定义动作则会调用它。您不受每个任务中动作数量的限制。
一个任务类的示例 (src/Tasks/MainTask.php
) 是:
<?php
declare(strict_types=1);
namespace MyApp\Tasks;
use Phalcon\Cli\Task;
class MainTask extends Task
{
public function mainAction()
{
// This is the default task and the default action
echo '000000' . PHP_EOL;
}
}
Phalcon\Cli\Task
或编写自己的类来实现任务,实现Phalcon\Cli\TaskInterface
. 动作¶
如上所述,我们指定了第二个参数为动作。任务可以包含多个动作。
<?php
declare(strict_types=1);
namespace MyApp\Tasks;
use Phalcon\Cli\Task;
class UsersTask extends Task
{
public function mainAction()
{
// This is the default task and the default action
echo '000000' . PHP_EOL;
}
public function regenerateAction(int $count = 0)
{
// This is the regenerate action
echo '111111' . PHP_EOL;
}
}
main
动作(默认动作): 或 regernate 动作: 参数¶
您还可以向动作传递参数。如何处理参数的示例可以在上面的示例引导文件中找到。
<?php
declare(strict_types=1);
namespace MyApp\Tasks;
use Phalcon\Cli\Task;
class UsersTask extends Task
{
public function mainAction()
{
echo '000000' . PHP_EOL;
}
public function addAction(int $first, int $second)
{
echo $first + $second . PHP_EOL;
}
}
Phalcon\Cli\Dispatcher
访问,这对传递标志或未知数量的参数时很有帮助。 <?php
declare(strict_types=1);
namespace MyApp\Tasks;
use Phalcon\Cli\Task;
class UsersTask extends Task
{
public function mainAction()
{
print_r( $this->dispatcher->getParams() );
}
}
链式调用¶
您还可以链式调用任务。为了按顺序运行它们,我们需要对引导部分进行一个小改动:我们需要将应用程序注册到 DI 容器中:
// ...
$console = new Console($container);
$container->setShared('console', $console);
$arguments = [];
// ...
假设我们要调用printAction()
元素Users
任务,我们只需要使用容器调用它。
<?php
namespace MyApp\Tasks;
use Phalcon\Cli\Console;
use Phalcon\Cli\Task;
/**
* @property Console $console
*/
class UsersTask extends Task
{
public function mainAction()
{
# This is the default task and the default action
echo '000000' . PHP_EOL;
# Also handle the `print` action
$this->console->handle(
[
'task' => 'main',
'action' => 'print',
]
);
}
public function printAction()
{
# Print action executed also
echo '444444' . PHP_EOL;
}
}
Phalcon\Cli\Task
并在那里实现你的逻辑。 模块¶
命令行应用程序也可以处理不同的模块,与MVC应用程序相同。你可以在CLI应用程序中注册不同的模块来处理CLI应用程序的不同路径。这允许更好地组织代码并分组任务。
你可以注册一个frontend
和backend
控制台应用程序的模块如下:
<?php
declare(strict_types=1);
use Exception;
use MyApp\Modules\Backend\Module as BackendModule;
use MyApp\Modules\Frontend\Module as FrontendModule;
use Phalcon\Autoload\Loader;
use Phalcon\Cli\Console;
use Phalcon\Cli\Dispatcher;
use Phalcon\Di\FactoryDefault\Cli as CliDI;
use Phalcon\Exception as PhalconException;
use Throwable;
$loader = new Loader();
$loader->setNamespaces(
[
'MyApp' => 'src/',
]
);
$loader->register();
$container = new CliDI();
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace('MyApp\Tasks');
$container->setShared('dispatcher', $dispatcher);
$console = new Console($container);
$console->registerModules(
[
'frontend' => [
'className' => BackendModule::class,
'path' => './src/frontend/Module.php',
],
'backend' => [
'className' => FrontendModule::class,
'path' => './src/backend/Module.php',
],
]
);
$arguments = [];
foreach ($argv as $k => $arg) {
if ($k === 1) {
$arguments['task'] = $arg;
} elseif ($k === 2) {
$arguments['action'] = $arg;
} elseif ($k >= 3) {
$arguments['params'][] = $arg;
}
}
try {
$console->handle($arguments);
} catch (PhalconException $e) {
fwrite(STDERR, $e->getMessage() . PHP_EOL);
exit(1);
} catch (Throwable $throwable) {
fwrite(STDERR, $throwable->getMessage() . PHP_EOL);
exit(1);
} catch (Exception $exception) {
fwrite(STDERR, $exception->getMessage() . PHP_EOL);
exit(1);
}
frontend
和backend
目录中。 方法¶
CLI应用程序提供了以下方法:
返回默认的模块名称 通过模块名称获取在应用程序中注册的模块定义 返回在应用程序中注册的模块 注册应用程序中存在的模块数组 如果路由器未返回有效的模块,则设置要使用的模块名称路由¶
CLI应用程序有自己的路由器。默认情况下,Phalcon CLI应用程序使用Phalcon\Cli\Router object, but you can implement your own by using the Phalcon\Cli\RouterInterface.
Default Routes¶
Similar to an MVC application, the Phalcon\Cli\Router使用Phalcon\Cli\Router\Route对象来存储路由信息。你始终可以通过实现Phalcon\Cli\Router\RouteInterface.
这些路由支持正则表达式参数,例如a-zA-Z0-9
,还提供额外的占位符:
占位符 | 描述 |
---|---|
:module | 模块(需要先设置模块) |
:task | 任务名称 |
:namespace | 命名空间名称 |
:action | 动作 |
:params | 任何参数 |
:int | 是否此为整数路由参数 |
默认路由是:
/:task/:action
/:task/:action/:params
如果你不希望使用默认路由,可以通过传递false
在构造时禁用它们Phalcon\Cli\Router对象:
关于路由和路由类的更多详细信息,可以参考路由页面上找到。
事件¶
Phalcon中的CLI应用程序是支持事件的,允许你使用setEventsManager
和getEventsManager
方法访问事件管理器。以下是可用的事件:
事件 | 停止 | 描述 |
---|---|---|
afterHandleTask | 是 | 在任务处理后调用。它允许你在任务执行后执行操作。 |
afterStartModule | 是 | 在处理模块后调用(如果使用了模块)。适用于模块执行后的后处理任务。 |
beforeHandleTask | 否 | 在任务处理前调用。它提供了在任务执行前执行操作的机会。 |
beforeStartModule | 是 | 在处理模块前调用(如果使用了模块)。适用于模块执行前的预处理任务。 |
boot | 是 | 在应用程序启动时调用。适用于在应用程序引导过程中执行操作。 |
如果你使用的是Phalcon\Cli\Dispatcher,你还可以利用beforeException
事件,该事件可以从调度器对象触发并停止操作。
这些事件为CLI应用程序生命周期的不同阶段提供了钩子,使你能够在应用程序流程的特定点执行自定义逻辑。