name Illuminate\Foundation\Console; class Kernel implements KernelContract { public function handle($input, $output = null) { try { $this->bootstrap(); return $this->getArtisan()->run($input, $output); } catch (Exception $e) { $this->reportException($e); $this->renderException($output, $e); return 1; } catch (Throwable $e) { $e = new FatalThrowableError($e); $this->reportException($e); $this->renderException($output, $e); return 1; } } } namespace Symfony\Component\Console; class Application { //执行命令 public function run(InputInterface $input = null, OutputInterface $output = null) { ...... try { $exitCode = $this->doRun($input, $output); } catch { ...... } ...... return $exitCode; } public function doRun(InputInterface $input, OutputInterface $output) { //解析出命令名称 $name = $this->getCommandName($input); //解析出入参 if (!$name) { $name = $this->defaultCommand; $definition = $this->getDefinition(); $definition->setArguments(array_merge( $definition->getArguments(), array( 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name), ) )); } ...... try { //通过命令名称查找出命令类(命名空间、类名等) $command = $this->find($name); } ...... //运行命令类 $exitCode = $this->doRunCommand($command, $input, $output); return $exitCode; } protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) { ...... //执行命令类的run方法来处理任务 $exitCode = $command->run($input, $output); ...... return $exitcode; } }
执行命令时主要有三步操作:
通过命令行输入解析出命令名称和参数选项。
通过命令名称查找命令类的命名空间和类名。
执行命令类的run方法来完成任务处理并返回状态码。
和命令行脚本的规范一样,如果执行命令任务程序成功会返回0, 抛出异常退出则返回1。
还有就是打开命令类后我们可以看到并没有run方法,我们把处理逻辑都写在了handle方法中,仔细查看代码会发现run方法定义在父类中,在run方法会中会调用子类中定义的handle方法来完成任务处理。 严格遵循了面向对象程序设计的SOLID 原则。
结束应用
执行完命令程序返回状态码后, 在artisan中会直接通过exit($status)函数输出状态码并结束PHP进程,接下来shell进程会根据返回的状态码是否为0来判断脚本命令是否执行成功。
到这里通过命令行开启的程序进程到这里就结束了,跟HTTP内核一样Console内核在整个生命周期中也是负责调度,只不过Http内核最终将请求落地到了Controller程序中而Console内核则是将命令行请求落地到了Laravel中定义的各种命令类程序中,然后在命令类里面我们就可以写其他程序一样自由地使用Laravel中的各个组件和注册到服务容器里的服务了。