Home > Mobile >  method @returns a child class of an property
method @returns a child class of an property

Time:04-10

I have a abstract class Foo and a abstract builder FooBuilder

abstract class Foo {

}

class Bar extends Foo {

}

abstract class FooBuilder {
  protected Foo $model;

  /**
  * Return the class instance
  *
  * @return Model  //What is the correct return type?? 
  */
  public function get()
  {
    return $this->model;
  }
}

abstract class BarBuilder {
  public function __construct()
  {
    $this->model = new Bar();
  }
}

I want use the method get in my child Builders and the IDE detect that the return type is the child class, not the abstract Foo

$barBuilder = BarBuilder();
$bar = $barBuilder->get(); //The type is "Bar", but IDE thinks is "Foo"

There is an way of return a static type of a attribute not the class in phpDoc? Something like @return static($this->model)?

An example is what Laravel's Eloquent does in SomeModel::find(). The IDE knows that the type can be SomeModel. But the @return only have Model.

CodePudding user response:

You should probably use Foo as the return type in your example; but for fun, you can use static return type to determine child instance like below

class Foo
{
    /**
     * @return string
     */
    public function Iam(): string
    {
        return "hello";
    }
}

class Helper
{
    /**
     * Return the class instance
     *
     * @return static
     */
    public static function get(): static
    {
        return new self();
    }
}

class FooBuilder extends helper
{
    protected Foo $model;

    public function mememe()
    {
        echo "I am a method";
    }
}

class FooBuilder2 extends helper
{
    protected Foo $model;

    public function xray()
    {
        echo "I am a method";
    }
}

$test = FooBuilder::get();
$test->mememe();

$test2 = FooBuilder2::get();
$test2->xray();

CodePudding user response:

Using generics in docblock does help PhpStorm(mine is 2021.2.2):

class Foo
{
}

/**
 * @template T of Foo
 */
class FooBuilder
{
    /**
     * @var T
     */
    protected Foo $model;

    /**
     * @return T
     */
    public function get(): Foo
    {
        return $this->model;
    }
}

class Child extends Foo
{
    public function testCompletion(){}
}

/**
 * @extends FooBuilder<Child>
 */
class ChildBuilder extends FooBuilder
{
}

class AnotherChild extends Foo
{
    public function otherMethod(){}
}

/**
 * @extends FooBuilder<AnotherChild>
 */
class AnotherChildBuilder extends FooBuilder
{
}

$childBuilder = new ChildBuilder();
$childBuilder->get()->testCompletion(); // testCompletion is suggested

$anotherChildBuilder = new AnotherChildBuilder();
$anotherChildBuilder->get()->otherMethod(); // otherMethod is suggested
  • Related