Skip to content

Conversation

deadLocks21
Copy link

@deadLocks21 deadLocks21 commented Jun 3, 2025

Description

This PR addresses PHPStan errors related to template type variance in Doctrine's metadata classes. The errors were occurring because the template type T was declared as covariant but was being used in an invariant position in the getReflectionClass() method.

The Problem

The following errors were reported by PHPStan:

  • Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\ODM\MongoDB\Mapping\ClassMetadata::getReflectionClass()
  • Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\ORM\Mapping\ClassMetadataInfo::getReflectionClass()
  • Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\Persistence\Mapping\ClassMetadata::getReflectionClass()

The Solution

We removed the -covariant modifier from the template type declarations in:

  • MongoClassMetadataInfo.stub
  • ORM/Mapping/ClassMetadata.stub
  • ORM/Mapping/ClassMetadataInfo.stub
  • Persistence/Mapping/ClassMetadata.stub

Why This Works

The covariance modifier was inappropriate in this case because:

  1. The getReflectionClass() method returns a ReflectionClass<T>
  2. This return type must be exactly of the specified type, not a subtype or supertype
  3. When a type parameter is used in an invariant position (like a return type), it should not be declared as covariant

Issues

#646

@mroeling
Copy link

What is the expected moment to have this merged please? We want to upgrade to php8.4 but this is a blocking issue!

@ondrejmirtes
Copy link
Member

@mroeling Please describe what error are you experiencing and why it's blocking you from upgrading to 8.4. It'd be helpful in helping me underseand why this change is needed.

@mroeling
Copy link

mroeling commented Aug 27, 2025

@mroeling Please describe what error are you experiencing and why it's blocking you from upgrading to 8.4. It'd be helpful in helping me understand why this change is needed.

Ofc, no problem.
Running phpstan on our code raises errors causing phpStan to fail.

Info:
phpstan level 4
Ubuntu 24.04 LTS
php 8.4.11

Line   deploy/app/vendor/phpstan/phpstan-doctrine/stubs/MongoClassMetadataInfo.stub                                                                                            
 ------ -----------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  40     Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\ODM\MongoDB\Mapping\ClassMetadata::getReflectionClass().   
 ------ -----------------------------------------------------------------------------------------------------------------------------------------------------------------------  


 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  Line   deploy/app/vendor/phpstan/phpstan-doctrine/stubs/ORM/Mapping/ClassMetadataInfo.stub                                                                                 
 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  59     Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\ORM\Mapping\ClassMetadataInfo::getReflectionClass().   
 ------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------  


 ------ -----------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  Line   deploy/app/vendor/phpstan/phpstan-doctrine/stubs/Persistence/Mapping/ClassMetadata.stub                                                                                 
 ------ -----------------------------------------------------------------------------------------------------------------------------------------------------------------------  
  20     Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\Persistence\Mapping\ClassMetadata::getReflectionClass().   
 ------ -----------------------------------------------------------------------------------------------------------------------------------------------------------------------  


 [ERROR] Found 3 errors

So basically we are waiting for this change to get into the mainstream so that we can test with php8.4. Using php8.4-fpm there is no issue, but for CLI this is blocking.
For comparison, cli php8.3 does not raise errors (obviously).

@ondrejmirtes
Copy link
Member

Please show the path where you're running PHPStan from, the path to bin/phpstan. There is something atypical about your setup. These errors from vendor stubs are usually filtered and not showed.

@mroeling
Copy link

mroeling commented Aug 27, 2025

We use phing as "executor".

From the root (=phing.dir), the vendor map is in deploy/app/vendor
phpstan is run as deploy/app/vendor/bin/phpstan analyze

    <property name="phpStanBinary"
              value="${phing.dir}/deploy/app/vendor/bin/phpstan"
              override="no"/>
              
                <exec executable="${phpStanBinary}"
                      passthru="true"
                      checkreturn="true"
                      dir="${phing.dir}"
                >
                    <arg value="analyze"/>
                    <arg line="--memory-limit 2G"/>
                    <arg line="--no-progress"/>
                    <arg path="${phing.dir}/deploy/app/include"/>
                    <arg path="${phing.dir}/deploy/app/config"/>
                    <arg path="${phing.dir}/deploy/app/services"/>
                    <arg path="${phing.dir}/tests"/>
                </exec>

The getReflectionClass() functions from these 3 Doctrine classes are called within our codebase, in the deploy/app/include folder

@ondrejmirtes
Copy link
Member

That looks okay. Personally I'd try this:

              
                <exec executable="vendor/bin/phpstan"
                      passthru="true"
                      checkreturn="true"
                      dir="${phing.dir}/deploy/app"
                >
                    <arg value="analyze"/>
                    <arg line="--memory-limit 2G"/>
                    <arg line="--no-progress"/>
                    <arg path="include"/>
                    <arg path="config"/>
                    <arg path="services"/>
                    <arg path="tests"/>
                </exec>

Typically people don't run PHPStan with these absolute paths and that might be throwing off the filtering logic.

These bug(s) still need to be fixed, I just want to help you meanwhile.

@mroeling
Copy link

These bug(s) still need to be fixed, I just want to help you meanwhile.

Much appreciated! I'll give it a try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants