PHPStan : howto get child type returned, not parent

485 Views Asked by At

I spent time reading PHPStan documentation and trying, but I don't understand how to get the child class detected by PHPStan in this code, or even if it is possible...

<?php declare(strict_types = 1);

abstract class Bar {}
    
class Foo extends Bar 
{
}
    
class Foofoo extends Bar 
{
}
    
class Baz
{
    private Bar $_bar;
        
    /**
     * @param Bar $bar
     *
     * @return void
     */
    public function setBar(Bar $bar)
    {
        $this->_bar=$bar;
    }
    
    /**
     *
     * @return Bar
     */
    public function bar(): Bar
    {
        return $this->_bar;
    }
}
   
$baz=new Baz();
$baz->setBar(new Foo());
\PHPStan\dumpType($baz->bar());     // return type is Bar, I would like Foo
$baz->setBar(new Foofoo());
\PHPStan\dumpType($baz->bar());     // return type is Bar, I would like Foofoo

The link to the playground : https://phpstan.org/r/53aebcc3-717b-445c-8715-0f277151270b

Thanks for your help !

1

There are 1 best solutions below

0
On

According to the founder of PHPStan (see Github discussion):

The only way to achieve this is with generics: https://phpstan.org/r/5ed2bf49-e9fe-43b6-b279-182458ff358a

<?php declare(strict_types = 1);

abstract class Bar {
}

class Foo extends Bar 
{
}

class Foofoo extends Bar 
{
}

/** @template T of Bar */
class Baz {
    private Bar $_bar;

    /**
     * @param T $bar
     *
     * @return void
     */
    public function setBar(Bar $bar)
    {
        $this->_bar=$bar;
    }
    
    /**
    *
    * @return T
    */
    public function bar(): Bar
    {
        return $this->_bar;
    }
}

/** @var Baz<Foo> */
$baz=new Baz();
$baz->setBar(new Foo());
\PHPStan\dumpType($baz->bar());     // return type is Bar, I would like Foo
$baz->setBar(new Foofoo());
\PHPStan\dumpType($baz->bar());     // return type is Bar, I would like Foofoo