bmewburn / vscode-intelephense

PHP intellisense for Visual Studio Code
https://intelephense.com
Other
1.61k stars 94 forks source link

Autocompletion: inexplicable behaviour for different PHP-Intelephense versions #2843

Closed Maschga closed 5 months ago

Maschga commented 5 months ago

Hi!

Describe the bug I have a Laravel-Project (Version 10) for which I use VSCode (Version 1.88.0) and PHP Intelephense. This framework has its own ORM called Eloquent. Every table in a database is represented by a class in PHP which inherits from the Illuminate\Database\Eloquent\Model-class. In my example below I created an Appointment-model. With these classes you are able to filter the entries in the table (for example with the Appointment::find()-method) or to retrieve all entries from the table (for example with the Appointment::all()-method). However, the Illuminate\Database\Eloquent\Model-class does not define the methods with which you are able to filter the entries. So in my example the IDE would only be able to autocomplete the method all() but not the (nevertheless available) where()-method. Therefore, the Laravel-IDE-Helper-package creates two files (_ide_helper.php and _ide_helper_models.php) to define the filter-methods and to make them visible for the IDE and tools like PHP Intelephense. However this does not work for the current version of PHP Intelephense (1.10.4). So I tried other versions and found out that the versions 1.0.1 - 1.8.2 do not raise any errors but the versions 1.9.0 - 1.10.4 do so. Unfortunately, I don't have any clue why PHP Intelephense does not recognize these methods any more or whether I'm doing something wrong. I had a look at the CHANGELOG.md but I didn't find something interesting. That's why the title of this issue is not very informative (feel free to change the title to a better one).

To Reproduce I created four files to reproduce it:

  1. Appointment.php:

    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Appointment extends Model {}
    
    // PHP Intelephense Version 1.0.1 - 1.8.2:
    Appointment::all(); // autocompleted
    Appointment::find(); // autocompleted
    
    // PHP Intelephense Version 1.9.0 - 1.10.4:
    Appointment::all(); // autocompleted
    Appointment::find(); // Error: Undefined method 'find'.
  2. Model.php:

    <?php
    
    namespace Illuminate\Database\Eloquent;
    
    class Model {
      public static function all() {}
    }
  3. _ide_helper_models.php:

    <?php
    
    namespace App\Models {
      class Appointment extends \Eloquent {}
    }
  4. _ide_helper.php:

    <?php
    
    namespace {
      class Eloquent extends \Illuminate\Database\Eloquent\Model {
          public static function find() {}
      }
    }

You might want to download this .zip so you do not have to create these files: src.zip

Expected behavior The where()-method should be found from PHP Intelephense and shown in the autocompletion-popup.

Screenshots Autocompletion when using the version 1.8.2: version_1 8 2 Autocompletion when using the version 1.10.4: version_1 10 4

Platform and version OS: Windows 10, Intelephense version specified above

Thank you in advance! ~ Maschga

bmewburn commented 5 months ago

When intelephense comes across a name clash like this it treats the classes as partial classes and merges them. However it doesn't accept multiple inheritance which is what is happening here by extending \Eloquent in one and Model in the other. It did in the previous versions but it became too complex with addition of other features like templates.

To resolve this you can either:

  1. Extend \Eloquent in your real models. I believe laravel sets this as a runtime alias for Illuminate\Database\Eloquent\Model anyway, and then it will pickup the methods defined on \Eloquent in the ide helper files.
  2. If you have the premium version of intelephense you can add @mixin \Eloquent to the docblock of your model.