larastan icon indicating copy to clipboard operation
larastan copied to clipboard

`Model::create()` issue with generics

Open pxlrbt opened this issue 2 years ago • 3 comments

  • Larastan Version: 2.0.1
  • --level used: 5
  • Pull request with failing test:

Description

Not sure whether this is an issue with Larastan, Laravels type definitions or even PhpStan itself: When running the Model::create() function on a class-string with a template definition, that's causing an issue. Seems like PhpStan cannot figure out the correct type.

Method Domain\Document\Actions\Action::run() should return T of  
    Domain\Document\Models\Document but returns Domain\Document\Models\Document.

Laravel code where the issue was found

Simplified setup for the models:

abstract class Document extends Model {}

class Tour extends Document {}

class Analysis extends Document {}

Actual code which throws error

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

But this works:

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

pxlrbt avatar Mar 04 '22 08:03 pxlrbt

Hi,

I tried to replicate this. And I think this can be an issue with PHPStan. I'll try to prepare an example and open an issue there.

Thanks.

canvural avatar Mar 04 '22 11:03 canvural

Thank you!

pxlrbt avatar Mar 04 '22 12:03 pxlrbt

Getting the same issue with Model::find()

/**
 * @template T of Model
 * @param class-string<T> $modelClassName
 * @return T|null
 */
function findModel(string $modelClassName, int $id): ?Model
{
    return $modelClassName::find($id);
}

Gives the PHPStan error:

Function findModel() should return (T of Illuminate\Database\Eloquent\Model)|null but returns Illuminate\Database\Eloquent\Model|null.

@canvural Did you ever make that issue in PHPStan?

mwnciau avatar Feb 14 '23 15:02 mwnciau