Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:116880 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 93146 invoked from network); 13 Jan 2022 15:27:02 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 13 Jan 2022 15:27:02 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id B179B1804B4 for ; Thu, 13 Jan 2022 08:36:31 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-ua1-f44.google.com (mail-ua1-f44.google.com [209.85.222.44]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 13 Jan 2022 08:36:31 -0800 (PST) Received: by mail-ua1-f44.google.com with SMTP id m90so12248298uam.2 for ; Thu, 13 Jan 2022 08:36:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dqxtech-net.20210112.gappssmtp.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=0o7ReCYAw4CEBFwSKqrZhw/TNMuj8rGWnnzDrjUV1DI=; b=fcklrinnP4Jj2y+V/EfiG04Q+Avlhv+r/yzJW2ut7zmDzLHjEpKv7VHQ/3lm/gsvbI vxzpJFIuT6JPJ3ZQLd/Vi6/1aCCoihVt4+yG6e7XRiCdPqb8lEoYg7AOCmEr/11e75jT 8GOtFVYOo0yD+mLrHOyONF6shD6gyO5MLmfVn3iw3uxbt5OvKCx+pZmAxNDzCphOfchl qPoIrN59K2y1PVTgUnz2ArP8U/2+O9Bw1etOgekHAqjgzqJu+Jg6kBIrJDtqimZ1oOXL oojkenvahDSfFYQdHfx7t5FA/0hJs9uBUKslym74ij23wkkTCIItTHrzzajRqe5PJwYZ JHPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=0o7ReCYAw4CEBFwSKqrZhw/TNMuj8rGWnnzDrjUV1DI=; b=SXhuBuBuJ0HrqXmJGrpVydAcH2iYdF9AFF2MRVbuMl7+pEnMb97CQ02NMIrA00vkTl +c3IoF+pwUXaLDHlkKtnKKx76KzekHrmYcPca+6d6XjSSlefFTYprYMb0v5yp8W+3xM2 kqFHUFKHXO2bl7uPWxaBzHEMdnTCpxHc/UeiyO37t9uMolZcutkUWpGYo7KxTZFHWeC6 d2IAUU6znaIiKgcmDZmNMfoGhd3F75sTd6RNTW1s4GE0PJF7Vgh9TNM+oE3lDxD//Rq1 mK4sg2ABskn1h7XwYh8ma5AIXIM6jm3d8fXOC/BKsyOLPyi0a7G42jkja4HAHOAwK5EV CbXg== X-Gm-Message-State: AOAM531t3NNjGe6Xd6s0f2r/HrJRplDbDxVoacZQJapsS0Q9k+wZ7I0r liynyiBgHb5uMc++oUcCRQNAPCGPY5vf4g+nmcSqYYCL6Z22Zg== X-Google-Smtp-Source: ABdhPJykBRjhmPRyORm95cggS0Vi+198w1J0Yr/9P7ziHYAn9BfIPljJbNIoWUf1fMouHLS7nBO2ueYtDQ49IuC4Apc= X-Received: by 2002:ab0:5e81:: with SMTP id y1mr2573374uag.23.1642091790193; Thu, 13 Jan 2022 08:36:30 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: Date: Thu, 13 Jan 2022 17:36:19 +0100 Message-ID: To: PHP internals Content-Type: text/plain; charset="UTF-8" Subject: Re: Trait constructors / property initialization From: andreas@dqxtech.net (Andreas Hennings) On Thu, 13 Jan 2022 at 15:36, Andreas Hennings 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