Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Take into account the dynamic Kernel class #374

Closed
Neirda24 opened this issue Dec 20, 2023 · 16 comments
Closed

Take into account the dynamic Kernel class #374

Neirda24 opened this issue Dec 20, 2023 · 16 comments

Comments

@Neirda24
Copy link

Neirda24 commented Dec 20, 2023

The kernel class in tests can be dynamic. But the property Kernel is type hinted with the interface which is not wrong of course but can be limiting.

There is no way (AFAIK) to tell PHPStan that my kernel class is App\Tests\Kernel and that the method xxx() always exists.

It should infer the type from the getKernelClass method in each test to determine the actual type.

At least make it Generic so we can @extends KernelTestCase<ClassOfKernel>

@ondrejmirtes
Copy link
Member

Please show a piece of code that makes PHPStan report an issue (and which issue).

@Neirda24
Copy link
Author

How ? It involves the symfony classes which uses $_SERVER and $_ENV global variable ? Should I only provide the userland code that raise an issue ?

@ondrejmirtes
Copy link
Member

Yes. PHPStan reports an error for your code that you're trying to solve here. I want to see that piece of code.

@Neirda24
Copy link
Author

Ok.

Given I am in a symfony context (6.4 here but doesn't really matter as it also applies to later versions), with the following :

  • Kernel class
<?php

namespace App\Tests;

final class Kernel extends \App\Kernel
{
    public function doSomething(): void
    {
    }
}
  • ./.env.test
KERNEL_CLASS='App\Tests\Kernel'
  • a custom test that must consume the custom function in the custom kernel
// ...

    public function testSomething(): void
    {
        self::ensureKernelShutdown();
        self::bootKernel();

        static::$kernel->doSomething();
    }

// ...

Produces the following error :

 ------ ------------------------------------------------------------------------------------------------------- 
  Line   MyTest.php                                          
 ------ ------------------------------------------------------------------------------------------------------- 
  123    Call to an undefined method Symfony\Component\HttpKernel\KernelInterface::doSomething().  
 ------ ------------------------------------------------------------------------------------------------------- 

@ondrejmirtes
Copy link
Member

There's no way for a PHPStan extension to provide means to override the property type.

Your best bet is a stub file in your project: https://phpstan.org/user-guide/stub-files

That looks something like this:

<?php

namespace Symfony\Bundle\FrameworkBundle\Test;

abstract class KernelTestCase
{

    /**
     * @var \App\Tests\Kernel
     */
    protected static $kernel;

}

@Neirda24
Copy link
Author

Will do on my project but waht could we do as a more global solution ?

Maybe we should wrap the static::$kernel in a getKernel() method ?

Or at least make the KernelTestCase class generic so we can provide the Kernel class we use in our test ?

@Neirda24
Copy link
Author

I also just tried

/**
 * @method static class-string<\App\Tests\Kernel> getKernelClass()
 */
class MyTest extends KernelTestCase
{
}

to specify the Kernel class of the method but it didn't worked out either :/

@ondrejmirtes
Copy link
Member

Yes, both are possible. Creating and overriding getKernel() method would be nice, provided projects typically have their own project-specific subclasses. That way you could override getKernel() method with a more specific return type, even native one.

Or at least make the KernelTestCase class generic

Yes, that's also possible, but I don't know how many projects typically have their own Kernel subclass with more methods to warrant making KernelTestCase generic because of the Kernel class name.

@ondrejmirtes
Copy link
Member

Just tried the @method approach - it works https://phpstan.org/r/eae3bf1c-1a62-4878-ab00-ae432f9b5b81.

As there's currently no actionable to-do here, I'm closing this issue.

@Neirda24
Copy link
Author

Sorry I just tried like I said and it didn't worked at all. I still get the Call to an undefined method Symfony\Component\HttpKernel\KernelInterface:: doSomething().

Also ok for closing but where should we discuss about the generic approach ? Because Kernel----TestCase it would make sense to have it generic on Kernel no ?

@ondrejmirtes
Copy link
Member

Sorry I just tried like I said and it didn't worked at all

Issues like these should be reproducible on phpstan.org/try. So I'd like to see your problem reproduced there.

where should we discuss about the generic approach

I don't have any data about how widespread this problem is. Probably not a lot since you're the first one asking about this :) Making a class generic should be justifiable because it puts a certain burden on all its users.

@Neirda24
Copy link
Author

Ok I think I managed to reproduce teh bug : https://phpstan.org/r/f6bc4123-0911-4961-97b0-f11a55c90c7f

@ondrejmirtes
Copy link
Member

I don't see the bug. You're overriding getKernelClass method but you're accessing kernel property.

@Neirda24
Copy link
Author

I understand. But at that point the type should be known to be of type Kernel instead of KernelInterface am I wrong ? Because by overriding that class the new is using that class-string thus the type should be Kernel or children.

@ondrejmirtes
Copy link
Member

But all of that code is in KernelTestCase that doesn't have the @method annotation.

See: https://phpstan.org/user-guide/troubleshooting-types

PHPStan doesn’t descend into a called function’s body to see what’s going on there. The native types, the PHPDocs, and the registered dynamic return type and type-specifying extensions are everything that’s used to figure out how the types are going to impacted.

Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants