barryvdh / laravel-ide-helper

IDE Helper for Laravel
MIT License
14.17k stars 1.16k forks source link

PHP 8.2 - Ide helper files seem not recognized #1402

Closed karinarastsinskagia closed 7 months ago

karinarastsinskagia commented 1 year ago

Versions:

Description:

After the update to PHP 8.2 all @Property annotations which include in _ide_helper_models.php are not recognized and an Access to an undefined property is thrown. More specifically, I have the following model and the respective _ide_helper_models.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

/**
 * @mixin IdeHelperArticle
 */
class Article extends Model
{

    protected $fillable = ['title'];

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }
}
<?php

// @formatter:off
/**
 * A helper file for your Eloquent Models
 * Copy the phpDocs from this file to the correct Model,
 * And remove them from this file, to prevent double declarations.
 *
 * @author Barry vd. Heuvel <barryvdh@gmail.com>
 */

namespace App\Models{
/**
 * App\Models\Article
 *
 * @property int $id
 * @property string $title
 * @property string $created_at
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Comment[] $comments
 * @property-read int|null $comments_count
 * @method static \Database\Factories\ArticleFactory factory(...$parameters)
 * @method static \Illuminate\Database\Eloquent\Builder|Article newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|Article newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|Article query()
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereTitle($value)
 * @mixin \Eloquent
 * @noinspection PhpFullyQualifiedNameUsageInspection
 * @noinspection PhpUnnecessaryFullyQualifiedNameInspection
 */
    class IdeHelperArticle {}
}
includes:
    - ./vendor/nunomaduro/larastan/extension.neon

parameters:
    paths:
        - src

    level: 6

    tmpDir: build/phpstan
    reportStaticMethodSignatures: true
    checkModelProperties: true
    checkMissingIterableValueType: false
    checkGenericClassInNonGenericObjectType: false
    checkOctaneCompatibility: true

    scanFiles:
        - _ide_helper.php
        - _ide_helper_models.php

$article = new Article();
$article->title = 'Article 1';
echo $article->title;

All works fine with PHP Version 8.1. Although, using PHP 8.2 I get the mentioned error message (Access to an undefined property App\Models\Article::$title).

About the issue, I have tried 3 different approaches. Please find them below

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

/**
 * * App\Models\Article
 *
 * @property int $id
 * @property string $title
 * @property string $created_at
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Comment[] $comments
 * @property-read int|null $comments_count
 * @method static \Database\Factories\ArticleFactory factory(...$parameters)
 * @method static \Illuminate\Database\Eloquent\Builder|Article newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|Article newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|Article query()
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereTitle($value)
 * @mixin \Eloquent
 * @noinspection PhpFullyQualifiedNameUsageInspection
 * @noinspection PhpUnnecessaryFullyQualifiedNameInspection
 */
class Article extends Model
{

    protected $fillable = ['title'];

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }

}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

/**
 * @mixin IdeHelperArticle
 */

#[\AllowDynamicProperties] 
class Article extends Model
{

    protected $fillable = ['title'];

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }

}
<?php

// @formatter:off
/**
 * A helper file for your Eloquent Models
 * Copy the phpDocs from this file to the correct Model,
 * And remove them from this file, to prevent double declarations.
 *
 * @author Barry vd. Heuvel <barryvdh@gmail.com>
 */

namespace App\Models{
/**
 * App\Models\Article
 *
 * @property int $id
 * @property string $title
 * @property string $created_at
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Comment[] $comments
 * @property-read int|null $comments_count
 * @method static \Database\Factories\ArticleFactory factory(...$parameters)
 * @method static \Illuminate\Database\Eloquent\Builder|Article newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|Article newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|Article query()
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|Article whereTitle($value)
 * @mixin \Eloquent
 * @noinspection PhpFullyQualifiedNameUsageInspection
 * @noinspection PhpUnnecessaryFullyQualifiedNameInspection
 */
 #[\AllowDynamicProperties] class IdeHelperArticle {}
}

Is there any setting that I have to enable in order to make ide_helper_models.php be compatible with PHP 8.2 or is there any other solution in order to keep the functionality as it is in PHP 8.1? Does anyone know why my Model class doesn't work in the same way after the update to PHP 8.2?

Jefemy commented 1 year ago

This seems to just be an issue in general with using mixins in this way now. I initially thought this was a bug too and created an issue in phpstan/phpstan#8939 but after some discussion it makes sense. PHPStan is assuming that because the IdeHelper class has no __get/__set the properties attached to it are dynamic and since it has no #[\AllowDynamicProperties] by default it is ignoring those entirely on the main class.

ide-helper could theoretically get around this by adding a fake get/set or AllowDynamicProperties to its generated class but I feel like both of those are just workarounds for the fact that I don't think mixins were made to do something like this.

mfn commented 1 year ago

Wouldn't it be technically more correct if the classes generated in the helper file would actually extend \Illuminate\Database\Eloquent\Model?

There the __get is implemented.

karinarastsinskagia commented 1 year ago

Wouldn't it be technically more correct if the classes generated in the helper file would actually extend \Illuminate\Database\Eloquent\Model?

There the __get is implemented.

Well, it works, however I don't if, technically it's more correct

karinarastsinskagia commented 8 months ago

@barryvdh

Do you have any news on this?

Thank you