Laravelコア解読のCosolieカーネル


コンサート?コア
前の記事ではLaravelのHTTPカーネルを紹介しました。ネットワーク要求はアプリケーションへのアクセスからアプリケーション処理完了までの要求からHTTP応答のライフサイクル全体におけるHTTPカーネルがどのようにLaravelの各コアコンポーネントを動かしてタスクを完了するかを詳細に説明しました。HTTPを処理する以外に、健全なアプリケーションを要求する場合、計画タスク、非同期キューなどを実行する必要があります。Laravelは、アプリケーションがこれらのシーンを満足させるためにアーティファクトツールを設計し、各種コマンドをartistanツールで定義して非HTTP要求の各種シーンを満足させることができるように、artivanコマンドは、LaravelのCosolieカーネルにより、アプリケーションコアコンポーネントのスケジューリングを完了させてタスクを完了させる。今日はLaravel Cosolieカーネルのコアコードを勉強します。
カーネルバインディング
HTTPカーネルと同じように、アプリケーション初期化段階でカーネルバインディングの過程があり、Consoneカーネルをアプリケーションのサービス容器に登録しますか?それとも前の記事で引用したbootstrap/ap.phpのコードを引用しますか?

<?php
//     :       
$app = new Illuminate\Foundation\Application(
  realpath(__DIR__.'/../')
);

//     :       
$app->singleton(
  Illuminate\Contracts\Http\Kernel::class,
  App\Http\Kernel::class
);
// console    
$app->singleton(
  Illuminate\Contracts\Console\Kernel::class,
  App\Console\Kernel::class
);

$app->singleton(
  Illuminate\Contracts\Debug\ExceptionHandler::class,
  App\Exceptions\Handler::class
);

return $app;

Consolieカーネル \App\Console\Kernelは、Illuminate\Foundation\Console,から継承されています。Consolieカーネルにおいて、私たちはアーティファクトコマンドと定義アプリケーションで実行する計画タスクを登録することができます。

/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
  // $schedule->command('inspire')
  //     ->hourly();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
  $this->load(__DIR__.'/Commands');
  require base_path('routes/console.php');
}
Consolieカーネルを実装する場合、カーネルはアプリケーションの命令計画タスク(sheduleメソッドで定義されている計画タスク)を定義します。

public function __construct(Application $app, Dispatcher $events)
{
  if (! defined('ARTISAN_BINARY')) {
    define('ARTISAN_BINARY', 'artisan');
  }

  $this->app = $app;
  $this->events = $events;

  $this->app->booted(function () {
    $this->defineConsoleSchedule();
  });
}

応用解析Cosoneカーネルaritisanファイルのソースコードを確認してください。Consoneカーネルバインディングの完了後、サービス容器を通してconsolieカーネルオブジェクトを解析します。

$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);

$status = $kernel->handle(
  $input = new Symfony\Component\Console\Input\ArgvInput,
  new Symfony\Component\Console\Output\ConsoleOutput
);
コマンドタスクを実行
Consoneカーネルのオブジェクトを解析してから、コマンドラインからのコマンド要求を処理します。PHPはグローバル変数を通じていることを知っています。SERVER['argv']はすべてのコマンドライン入力を受信します。コマンドラインでshellスクリプトを実行するのと同じです。(shellスクリプトではスクリプトファイル名を0で取得できます。$1$2これらを順次取得してshellスクリプトに渡されるパラメータオプション)索引0はスクリプトファイル名に対応しています。次にコマンドラインでスクリプトに渡すすべてのパラメータオプションです。コマンドラインでは、アーティストスクリプトで実行されるコマンドは、アーティストスクリプトの中にあります。SERVER['argv']配列のインデックス0に対応する文字列は、常にアーティファクトという文字列であり、コマンドラインの後ろのパラメータは$uまで順次対応します。SERVER['argv']配列の後の要素にあります。
アーティファクトコマンドの文法ではコマンドパラメータのオプションが指定できますので、コマンドライン入力パラメータ解析の複雑さを減らすために、LaravelはSymfony\Component\Consolie\Inputオブジェクトを使ってコマンドライン内のこれらのパラメータオプションを解析します。shell関数getoptsで各種フォーマットのコマンドラインパラメータ入力を解析します。同じLaravelでSymfony\Component\Consolie\Outputオブジェクトを使用してコマンドラインの標準出力を抽象化します。
ブートアプリケーション
Consolieカーネルのhandleメソッドでは、HTTPカーネル処理要求の前にbootstrapherプログラムを使ってアプリケーションを引用するのと同じようにコマンドの処理を開始する前にもブートアプリケーションがあります。
その親類の「Illuminate FoundationConsoreKernel」の内部には、属性名の「bootstraphers」というガイドプログラムの配列が定義されています。

protected $bootstrappers = [
  \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
  \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
  \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
  \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
  \Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,
  \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
  \Illuminate\Foundation\Bootstrap\BootProviders::class,
];
配列に含まれるガイドプログラムは、基本的にはHTTPカーネルで定義されているブートプログラムと同様に、初期化段階で適用される環境変数、プロファイルローディング、異常プロセッサ登録、Consoneリクエストの設定、登録アプリケーションのサービス容器、Facadeおよび起動サービスです。ここで、Consoneの設定要求は、HTTPカーネルとは一意に異なるガイドプログラムである。
コマンドを実行
実行命令は、SymfonyフレームからSymfony\Component\Component\Appplicationクラスを引き継いで、対応するrun方法で実行されます。

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;
  }
}

コマンド実行時には主に3ステップの操作があります。
  • コマンドライン入力でコマンド名とパラメータオプションを解析します。
  • コマンド名からコマンドクラスの名前空間とクラス名を検索します。
  • は、コマンド類のrun方法を実行してタスク処理を完了し、状態コードを返す。
  • コマンドラインスクリプトの仕様と同様に、コマンドタスクプログラムを実行すれば0に戻り、異常終了したら1に戻ります。
    また、コマンドクラスを開くと、runの方法は見られません。処理ロジックをすべてhandleの方法に書いています。コードをよく見ると、runの方法は父の種類に定義されています。runの方法では、サブクラスで定義されているhandleの方法を呼び出してタスク処理を完了します。対象プログラムに対して設計されたSOLID原則を厳格に遵守した。
    アプリケーションを終了
    コマンドプログラムを実行してステータスコードに戻ると、artiisanで直接exit($status)関数で状態コードを出力し、PHPプロセスを終了します。次にshellプロセスは戻りの状態コードが0かどうかをもとにスクリプトコマンドの実行が成功したかを判断します。
    ここでコマンドラインで開くプログラムはここで終了します。HTTPカーネルと同じConsolieカーネルはライフサイクル全体でもスケジューリングされていますが、Httpカーネルは最終的に要求をControllerプログラムに落としました。Cosolieカーネルはコマンドラインの要求をLaravelで定義されている各種コマンドクラスのプログラムに落としました。そしてコマンドクラスでは、他のプログラムを書くように、Laravelの各コンポーネントとサービス容器に登録されたサービスを自由に利用できます。
    本論文はすでにシリーズの文章Laravelソースの勉強に収録されています。
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。