On Thu, 13 Jan 2022 at 15:36, Andreas Hennings <[email protected]> wrote:
>
> Hello list,
> I want to bring up a topic that has bothered me whenever I use traits.
> I don't have a solution proposal for it, yet, unfortunately.
> I was going to comment in the other thread about traits, but it seems
> better suited for a new discussion.
>
> ----------
>
> Traits allow to share code between classes of different inheritance chains.
> They can be used instead of composition, or they can be used to help
> with composition - e.g. a trait can expose functionality from a
> specific injected dependency.
>
> ----------
>
> When using base classes, we can follow a convention to always call the
> parent constructor.
> We can even make the properties in the base class private, to fully
> encapsulate them.
>
> But:
> When using properties in traits, how can I make sure that they are
> properly initialized in the class constructor?
I think I have a solution:
abstract properties in traits!
The idea would be:
- traits can have abstract properties that are private, protected or public.
- non-abstract classes cannot have abstract properties.
- class properties override trait properties, with some compatibility
requirements.
- non-abstract protected or public class properties from the parent
class also override trait properties.
- (optional) abstract classes can have abstract properties that are
protected or public.
- (optional) abstract class properties from a parent class are
overridden by the trait property, but with compatibility checks.
This implies that abstract trait properties _must_ be redeclared in
the class that uses the trait,
interface X {}
interface XHaving {
public function getX(): X;
}
trait T {
abstract private X $x;
public function getX(): X {return $this->x;}
}
class C implements XHaving {
use T;
public function __construct(
private X $x,
) {}
}
class D implements XHaving {
use T; // Error, must redeclare abstract property T::$x.
}
The benefit:
Properties are initialized in the same file where they are declared.
I don't know if we need aliasing for properties, perhaps we should
first go without that.
I did find a discussion about abstract properties in externals.io, but
this was for interfaces and classes, not for traits.
https://externals.io/message/64126#66682
>
> Also, what if I want to provide an init method with specific logic to
> set that property? How can I make sure that method will be called in
> the constructor?
This part would not be solved by the abstract properties.
But I think that's ok.
>
> I found that Psalm can detect "PropertyNotSetInConstructor", which is
> also applied to properties from traits.
> But this is not as straightforward as calling a parent constructor.
>
> Can and should we provide a language-level solution for this?
> Or should this be left to static analysis tools and IDEs?
>
> Cheers,
> Andreas
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php