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

Allow narrowing of type in PHPDoc #482

Closed
Jean85 opened this issue Sep 1, 2017 · 10 comments
Closed

Allow narrowing of type in PHPDoc #482

Jean85 opened this issue Sep 1, 2017 · 10 comments
Milestone

Comments

@Jean85
Copy link
Contributor

Jean85 commented Sep 1, 2017

Take this code as an example

<?php declare(strict_types = 1);

interface Animal
{}

class Bird implements Animal
{}

abstract class AnimalCage
{
    /** @var Animal[] */
    private $animals;

    /**
     * @return Animal[]
     */
    public function getAnimals(): array
    {
        return $this->animals;
    }

    /**
     * @return Bird[]
     */
    public function getBirds(): array
    {
        return array_filter($this->getAnimals(), function ($val) {
            return $val instanceof Bird;
        });
    }
}

The PHPDoc over getBirds() is marked as an error by PHPStan, because it's somehow expecting @return Animal:

 ------ ---------------------------------------------------------------- 
  Line   analyzed.php                                                    
 ------ ---------------------------------------------------------------- 
  27     Method AnimalCage::getBirds() should return Bird[] but returns  
         Animal[].                                                       
 ------ ---------------------------------------------------------------- 

I would like to restrict the type and not be forced to use the @return Animal[] | Bird[] workaround to avoid errors with PHPStan.

@JanTvrdik
Copy link
Contributor

JanTvrdik commented Sep 1, 2017

@Jean85 I have trouble understanding your problem. Can you reproduce it on https://phpstan.org/?

@Jean85
Copy link
Contributor Author

Jean85 commented Sep 1, 2017

Sorry, I had wrongly narrowed down my problem. I've edited my starting example with something that now gets you the error that I wanted to report.

@ondrejmirtes
Copy link
Member

The problem is here:

        return array_filter($this->getAnimals(), function ($val) {
            return $val instanceof Bird;
        });

Because array_filter return type is inferred from $this->getAnimals() and thats Animal[]. This is quite advanced code to be recognized and understood by PHPStan automatically, so I recommend you to store the result of array_filter into a variable, mark it with @var Bird[] and return that variable.

@ondrejmirtes
Copy link
Member

And about the original form of your question (which I retrieved from my email inbox):

interface AnimalCage
{
    public function getAnimal(): Animal;
}

class BirdCage implements AnimalCage
{
    /**
     * @return Bird
     */
    public function getAnimal(): Animal
    {
        // ...
    }
}

This is already supported and in case of Calling BirdCage::getAnimal(), PHPStan will assume that the return type is Bird, thanks to the fact that Bird implements Animal.

@JanTvrdik
Copy link
Contributor

@Jean85 Or use foreach with if. It's a lot faster and a lot easier to statically analyse https://phpstan.org/r/6ef813feadeb02536965559f5d1e59d7

@JanTvrdik
Copy link
Contributor

@Jean85 Turn's out that supporting the array_filter with single return statement in Closure is not that hard. I have a working implementation based on #476, so stay tuned for next version.

@Jean85
Copy link
Contributor Author

Jean85 commented Sep 1, 2017

Yeah great! Thanks @JanTvrdik

@ondrejmirtes I imagined that the issue whas somethat there while re-writing the example, thanks.

@ondrejmirtes ondrejmirtes added this to the 0.9 milestone Sep 1, 2017
@ondrejmirtes
Copy link
Member

@JanTvrdik #476 got merged, can you send your PR for array_filter Thanks :)

@JanTvrdik
Copy link
Contributor

@ondrejmirtes #561

@ondrejmirtes
Copy link
Member

Done, PR merged. Thanks to all!

@lock lock bot locked as resolved and limited conversation to collaborators Dec 20, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants