Open11

https://github.com/larastan/larastan/issues/1149

あかつかあかつか
class Action
{
    /**
     * @template T of \Domain\Document\Models\Document
     * @param  class-string<T>  $documentType
     * @return T
     */
    public function run(string $documentType): Document
    {
        return $documentType::create();
    }
}

このコードから推測するに、モデルは app/Domain/Document/Models/ におく?

あかつかあかつか

ちがう。トップレベルがDomainだから、オートロード設定で、Domainに紐づくディレクトリを決めてやらないといけない。

    "autoload": {
        "psr-4": {
            "App\\": "app/",
+           "Domain\\": "domain/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },

これで、dumo-autoloadを打つ

あかつかあかつか

とりあえず、Domain\Document\Modelsの名前空間のところにAction作ってphpstanかけてみる

Domain/Document/Models/Action.php
<?php

namespace Domain\Document\Models;

class Action
{
    /**
     * @template T of \Domain\Document\Models\Document
     * @param  class-string<T>  $documentType
     * @return T
     */
    public function run(string $documentType): Document
    {
        return $documentType::create();
    }

    /**
     * @template T of \Domain\Document\Models\Document
     * @param  class-string<T>  $documentType
     * @return T
     */
    public function run2(string $documentType): Document
    {
        $document = new $documentType();
        $document->save();
        return $document;
    }
}

run1のところでエラーが出る。
おそらく再現した

$ ./vendor/bin/phpstan analyse Domain/Document/Models/Action.php
Note: Using configuration file /Users/akinori/development/example-app/phpstan.neon.
 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ --------------------------------------------------------------------------------------------------------------------------------------------- 
  Line   Action.php                                                                                                                                   
 ------ --------------------------------------------------------------------------------------------------------------------------------------------- 
  :14    Method Domain\Document\Models\Action::run() should return T of Domain\Document\Models\Document but returns Domain\Document\Models\Document.  
         💡 Type Domain\Document\Models\Document is not always the same as T. It breaks the contract for some argument types, typically subtypes.     
 ------ --------------------------------------------------------------------------------------------------------------------------------------------- 


                                                                                                                        
 [ERROR] Found 1 error