On Thu, 13 Jan 2022 at 15:36, Andreas Hennings <andr...@dqxtech.net> 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