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