phplaravelphpstormtype-hintingphpdoc

PhpStorm: Is there a way to enforce a type on the return statement using an inline PHPDoc annotation?


Consider the following code:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Car extends Model
{
    public static function getTheFirstCar(string $color): ?self
    {
        /** @var ?self */ // <-- Doesn't apply! Is there any alternative?
        return (new self())->newQuery()->firstWhere('color', '=', $color);
    }
}

The code is working correctly; nevertheless PhpStorm complains:

Return value is expected to be 'Car|null',
'\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model' returned

PhpStorm PHPDoc Type Annotation on return statement

Assigning the result of the expression into an annotated variable resolves the warning, but yet introduces a "redundant" variable!

/** @var ?self $redundant */
$redundant = (new self())->newQuery()->firstWhere('color', '=', $color);
return $redundant;

So, is there a way in PhpStorm to enforce an inline type-annotation for the value of the return statement expression explicitly as Car|null, without introducing a redundant variable or specifying all of the expected return types?


Solution

  • You can suppress this warning by adding the @noinspection PhpIncompatibleReturnTypeInspection annotation before your statement.
    I personally would not do this, but it's the only answer to you your question about how to "enforce" the return type and suppress warning afaik.

        /** @noinspection PhpIncompatibleReturnTypeInspection */
        return (new self())->newQuery()->where('color', '=', $color)->first();
    

    If you decide to respect the warning, then this is probably the reason and solution for it: newQuery() will create a new query on the models table (most likely: cars) without setting the appropriate model (Car).
    Internally you're now running a bare query on cars. Therefore you will receive the appropriate record but is not gonna be an instance of Car, but an instance of Model instead. Therefore PhpStorm is expecting multiple additional return types here and printing this warning on your statement since it differs from the methods return type ?self.

    The quick solution is to change newQuery() into newModelQuery(). This will create a new query and set the Model Car on the created query and return the appropriate instance or null

    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Car extends Model
    {
        public static function getTheFirstCar(string $color): ?self
        {
            return (new self())->newModelQuery()->firstWhere('color', '=', $color);
            // I'd use this statement though:
            // return self::where('color', '=', $color)->first();
        }
    }