Search code examples
phpphpstan

phpstan: how to handle derived class return types


What's the right way to fix the error generated by phpstan for this sample code? The error message is:

Method Foo::foo() should return Child but returns Base.

<?php declare(strict_types = 1);

Interface MyI {
    abstract function a(): self;
}
Class Base implements MyI { 
    public function a(): self {return $this;} 
}
Class Child extends Base { 
    public function c(): self {return $this;} 
}
Class Foo {
    public function factory(): Child {
        return new Child();
    }
    /**
     * @return Child
     */
    public function foo() /* note no return type */  {
        return $this->factory()
            ->c()
            ->a();
    }
}

One way to eliminate the error is to change the @return to read:

/**
 * @return Child | Base
 */

But I greatly dislike that because foo() never returns an instance of Base. The code only ever works with the derived class Child. In fact, the interface and base classes are both in a library (dependency), so I mostly cannot even change that code.

I could re-implement a() in my Child class like this:

    public function a(): Child {
        parent::a();
        return $this;
    }

But that is also ugly, and worse, this is a toy example. In the real class, I'd have to re-implement many methods. Very bad.


Solution

  • You need @return static for that: https://phpstan.org/r/42ee409c-ada2-44c9-a26d-6a85c2327bca

    To learn about all different PHPDoc posibilities head to PHPStan documentation: