開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. PHP >
  4. Laravel >
  5. bootstrap/app.phpのないプロジェクトをLarastanで静的解析する

bootstrap/app.phpのないプロジェクトをLarastanで静的解析する

こんにちは、でぃーほりです。

今回は、Larastanについての記事です。

bootstrap/app.php がないLaravelプロジェクト -- パッケージ

例えば、複数のサブシステムからなるシステムを作る際、サブシステム横断的に使うものを共通化するためのプロジェクトを作ることがあります。

  • migration
  • Eloquent Model
  • config
  • ドメインロジック
  • etc.

package.png

以下、これをパッケージと呼びます。

パッケージは、単体ではWebアプリケーションとして動作しないので、 bootstrap/app.php や Kernel.php などを持ちません。

tree -d -L 1 common
common
|-- config
|-- database
|-- resources
|-- src
|-- tests
`-- vendor

bootstrap/app.php がないと、configが正しく設定されず、静的解析が失敗することがある

Larastanでは、configが正しく設定されていないと静的解析に失敗することがあります。

例えば、解析対象のコードにEloquent Modelのリレーションシップが含まれていると、DBのコネクションの設定が必要です。

bootstrap/app.php がないと、configが正しく読み込まれず、下記のようなエラーが出ます。

 ------ ------------------------------------------------------------------- 
  Line   Models/MyModel.php                                     
 ------ ------------------------------------------------------------------- 
         Internal error: Database connection [subsystem_a] not configured.  
         Run PHPStan with --debug option and post the stack trace to:   
         https://github.com/phpstan/phpstan/issues/new                  
 ------ ------------------------------------------------------------------- 

解消方法

configを読み込むための bootstrap/app.php を書きます。

<?php

declare(strict_types=1);

use NunoMaduro\Larastan\ApplicationResolver;

require __DIR__ . '/../vendor/autoload.php';

$app = ApplicationResolver::resolve();

$configFilepaths = glob(__DIR__ . '/../config/*');

assert($configFilepaths !== false);

foreach ($configFilepaths as $configFilepath) {
    $pathinfo = pathinfo($configFilepath);
    $configName = $pathinfo['filename'];
    $app->make('config')->set($configName, require $configFilepath);
}

return $app;

詳細

静的解析対象のLaravelプロジェクトにbootstrap/app.phpがない場合、 Larastanのbootstrap.php が使用されます。

執筆時点でのmaster HEADのコードを引用します。

...
use NunoMaduro\Larastan\ApplicationResolver;

define('LARAVEL_START', microtime(true));

if (file_exists($applicationPath = getcwd().'/bootstrap/app.php')) { // Applications and Local Dev
    $app = require $applicationPath;
} else { // Packages
    $app = ApplicationResolver::resolve();
}
...

静的解析対象がパッケージの場合、else句に入って\NunoMaduro\Larastan\ApplicationResolver::resolve() でApplicationが構築されます。

続いて、 ApplicationResolver.php を見てみます。

...
use Orchestra\Testbench\Concerns\CreatesApplication;

/**
 * @internal
 */
final class ApplicationResolver
{
    use CreatesApplication;

    /**
     * Creates an application and registers service providers found.
     *
     * @return \Illuminate\Contracts\Foundation\Application
     * @throws \ReflectionException
     */
    public static function resolve(): Application
    {
        $app = (new self)->createApplication();
...

\Orchestra\Testbench\Concerns\CreatesApplicationトレイトのcreateApplication()でApplicationを構築していることがわかります。

ここで構築されるApplicationには/vendor/orchestra/testbench-core/laravel/config/のコンフィグが読み込まれ、パッケージのconfigが読み込まれません。

ゆえに、自分でconfigを読み込ませる必要があったわけです。

まとめ

  • パッケージプロジェクトにLarastanをかけるときは、config読み込み用の bootstrap/app.php を用意する
TOPに戻る