对于Yii2而言,命令行应用和网页应用基本是相似的,添加一个命令行命令的过程,和添加一个action是同样的。网页应用的入口文件是web目录下的index.php,而命令行应用的入口文件在应用根目录下的yii(windows系统对应的是yii.bat),典型的入口文件以下:php
#!/usr/bin/env php <?php /** * Yii console bootstrap file. * * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ defined('YII_DEBUG') or define('YII_DEBUG', true); // fcgi doesn't have STDIN and STDOUT defined by default defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); defined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w')); require(__DIR__ . '/vendor/autoload.php'); require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php'); $config = require(__DIR__ . '/config/console.php'); $application = new yii\console\Application($config); $exitCode = $application->run(); exit($exitCode);
与web相比,有两个不一样的地方值得注意,一个是定义了标准输入输出,另一个是引入了console.php配置文件,相对的网页应用引入的是web.php。由于命令行应用和网页应用的应用场景不一样,所依赖的模块和组建也会差异很大,所以用不一样的配置文件,尽可能减小初始化没必要要的组建所带来的性能损失。linux
命令行应用一样遵循MVC结构,不一样的是V一般没有啦,通常只有Controller和Model。每一个Controller文件能够有多个action,调用方式和网页应用相似,例如:web
class ExampleController extends \yii\console\Controller { // 调用命令 "yii example/create test", 这里的$name会被赋值为test public function actionCreate($name) { ... } // 调用命令 "yii example/index city id" $category=city,$order=id public function actionIndex($category, $order = 'name') { ... } // 调用命令 "yii example/add test", 其中,$name = ['test'] // 调用命令 "yii example/add test1,test2" 其中,$name = ['test1', 'test2'] public function actionAdd(array $name) { ... } }
####模块内命令 为了简单耦合度,比较好的选择是讲命令行程序都封装到各个模块,而不是所有放在应用根目录下的commands目录下。那么怎么让命令行的各个controller也分部到各个模块里呢?关键就在于模块类的controllerNamespace这个成员变量。网页应用的模块,这个变量经过被设置成app\模块id\controllers,所以,若是是命令行的controller,一般放到模块内的commands目录下,所以这个命名空间就须要赋值成app\模块id\commands数据库
###调用bootstrap
####同步调用 php提供了好多调用命令行程序的方式,如exec,system,popen,等等。须要调用命令行程序的适合,只要组装相应地命令就好了。如 exec("php xxx/default/index abc"),就是调用xxx模块下地default控制器的index方法,参数传的是abc ####异步调用 须要涉及到命令行程序的场景,一般是执行时间较长的任务,好比发送邮件(若是邮件服务器繁忙,经常形成同步调用的状况下等待时间过长而30秒超时),爬虫抓取,或者执行一些大批量的数据库读写操做。这种场景下,网页程序只负责激活这个命令行程序,让其继续执行,页面不等待命令行执行结束,就返回了。代码以下:windows
if (substr(php_uname(), 0, 7) == "Windows") { pclose(popen("start /B ". $cmd, "r")); } else { $php = 'php'; exec($php.' '. $cmd . " > /dev/null &"); }
windows服务器和linux服务器有着不一样的处理方式。 ####socket调用 若是命令行程序和网页程序不在一个服务器上,远程调用,那么将命令行程序封装成socket服务,启动以后常驻内存中,网页端经过socket消息的方式,告诉socket服务程序执行相应地命令行程序,一样这里须要使用上一节提到的异步调用方式,socket服务器充当的是一个命令调度的角色,以多进程的方式,调用不一样的命令行程序。服务器