I want to ship a class A
that can be locally extended (LocalA
). Most methods need to return $this
so that calls can be chained. I'm looking for a way to type-hint the return values of the methods defined in A
(and LocalA
) to say "it returns the same class as the object upon which the method was called".
This way IDEs can offer up suggested methods following a call.
:self
is a language possibility but it won’t do. It would mean that after a method defined in A
, the IDE would see the result as being an A
and not a LocalA
:
<?php
class A {
function a():self {
return $this;
}
}
class B extends A {
function b():self {
return $this;
}
}
$o = new B();
$o->➊
$o->a()->➋
At ➊ the IDE will list possible methods a()
and b()
, but at ➋ it will only list a()
.
:static
would be nice, but is invalid, not supported/implemented in PHP.
The following looked promising as an answer, and PHP is happy with running it:
trait trait1 {
function a():self {
return $this;
}
}
trait trait2 {
function b():self {
return $this;
}
}
class A {
use trait1;
}
class B {
use trait1;
use trait2;
}
$o = new B();
$o->➊ // offers a() and b() ✔
$o->a()->➋ // offers only a() ✖ treats the trait's 'self' as that trait, I think.
...but annoyingly my language server (intellephense via coc-phpls) doesn't realise that 'self' from a trait should refer to B
and thereby include all of both traits.
I'm trying to build an importer class that takes data, does something. I'm using a fluent interface (so lots of return $this
). I want other third parties to be able to extend it by adding their own methods, but this whole thing is really about the developer experience, and so I'd like IDEs to be able to pickup the methods made available by plugins.
I have discovered that the following works, though am open to alternative answers too.
<?php
class A {
/**
* @return static
*/
public function a() { return $this; }
}
class LocalA {
/**
* @return static
*/
public function b() { return $this; }
}
$o = new LocalA();
$o->➊ // offers a() and b() ✔
$o->a()->➊ // offers a() and b() ✔
$o->a()->b()->➊ // offers a() and b() ✔
It seems a shame I can't actually specify this within the PHP language, though.