Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:101945 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 62845 invoked from network); 1 Mar 2018 13:43:25 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 1 Mar 2018 13:43:25 -0000 Authentication-Results: pb1.pair.com header.from=andreas@dqxtech.net; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=andreas@dqxtech.net; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain dqxtech.net from 74.125.82.50 cause and error) X-PHP-List-Original-Sender: andreas@dqxtech.net X-Host-Fingerprint: 74.125.82.50 mail-wm0-f50.google.com Received: from [74.125.82.50] ([74.125.82.50:36940] helo=mail-wm0-f50.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 49/71-25585-C73089A5 for ; Thu, 01 Mar 2018 08:43:25 -0500 Received: by mail-wm0-f50.google.com with SMTP id 139so11817833wmn.2 for ; Thu, 01 Mar 2018 05:43:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dqxtech-net.20150623.gappssmtp.com; s=20150623; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=xlC5+3fJjymEU/tt2fYlY3gXmaB6w1gxWDh6SWTq9oQ=; b=WSCoFkRjJDxj3mV2uAYJwgZC9GBzhlgdckSB0AS47HDXQtX9+gkSDrwRCcNBv40+Y3 zb2ZTZPiIqa68HmQefVOuqiMbGLvG0xjHWN78fBMDFf1eeeNVNJ4BCQt4WSB/2rXPgj3 YOxdkTLU5gDUuD/HBL+xfbKJ1ukZ491z96tFB4qnUKc66qMsN5pWmaj4Btm3xCwHfaJR jxHKbEPjqPI6ZwLWFFcDB/UGxnbWByJ+75JvmvhMVPb0ntSLcG7QQUFQFsT4YFGBJZJn m84RVp2Qi/z2DwCT7UrGkaqTcQVT05vJXkGMA2/tmMliR/NditknM/5p+Ko3qAaXCmVM 2H+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=xlC5+3fJjymEU/tt2fYlY3gXmaB6w1gxWDh6SWTq9oQ=; b=DeEl4aNhlDWxALyhEEf/Wcw1H1A3mKD6rEQ7TqH2SJTtFrkOG5IWKsCoc1OhUZQiSJ KG+qume+kuilPIdqS7uWaAxXa5iii8ev0LXT4LQ6MeGA5smuLcYuscNw0mri+4cG2cn0 vtHtVKtVepiGmn6J2vQwq/covFE8D9AVWaHcv7jgzcfhiTLeL466pZVOpjYdBN6z+Idz 0WGk9MskxtZ/mc3HFmDwdX55ecnSzlbINbwW4bTZmLnWHmDVQVNfY28f7w3bl9GMKOJL BzMktn+BWtUpZK6mf1fcn2s2VWpYH7HfxQcugRS/eQ9+6UMAHIuzNiZg4jP0sb65Ccm0 /M4g== X-Gm-Message-State: APf1xPBB++2cuIPVv2vK1O69l9WMb1PmvEG/Yn/2cf1HHbEJSwgaIdua XHAP0NJirClj1hl28PkRxLGPlbCK X-Google-Smtp-Source: AG47ELt8w5HqT5SVFBu5Caz3he5XZGXDfSxeisRe4+QcU4wmsFAHD6/UeZOwdUQtj/rKllk8jHj/Gw== X-Received: by 10.80.136.37 with SMTP id b34mr2978383edb.252.1519911801586; Thu, 01 Mar 2018 05:43:21 -0800 (PST) Received: from mail-wm0-f51.google.com (mail-wm0-f51.google.com. [74.125.82.51]) by smtp.googlemail.com with ESMTPSA id d6sm4425925edm.52.2018.03.01.05.43.20 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 01 Mar 2018 05:43:21 -0800 (PST) Received: by mail-wm0-f51.google.com with SMTP id x7so11767709wmc.0 for ; Thu, 01 Mar 2018 05:43:20 -0800 (PST) X-Received: by 10.46.114.26 with SMTP id n26mr1455399ljc.74.1519910285671; Thu, 01 Mar 2018 05:18:05 -0800 (PST) MIME-Version: 1.0 Received: by 10.25.225.78 with HTTP; Thu, 1 Mar 2018 05:17:45 -0800 (PST) In-Reply-To: References: Date: Thu, 1 Mar 2018 14:17:45 +0100 X-Gmail-Original-Message-ID: Message-ID: To: Marco Pivetta Cc: David Rodrigues , PHP Internals List Content-Type: text/plain; charset="UTF-8" Subject: Re: [PHP-DEV] Traits with interfaces From: andreas@dqxtech.net (Andreas Hennings) > don't use traits Yes, in general, yes. Composition is great, and I use it most of the time. I still do have some cases where I think that base classes (with private properties) are justified, and then some cases where either traits or multiple inheritance would be justified. We could agree to set this debate aside, and focus on the original proposal, assuming it is for those people who have a good reason to use traits. But I have a feeling that this part of the discussion ("traits are bad") isn't over. I will get back to it further below. > due to the previous point, inheriting a type from a trait becomes a dangerous BC boundary, easily broken by consumers of the trait when consumers alias or when the trait implementor adds a new interface implementation Yes. On the other hand, many traits out there really try to comply with an existing interface, and are meant as a replacement for additional base classes. The renaming is technically possible, but how often does it occur in reality? So what about this modified proposal: - A trait can "promise" to comply with an interface. We could use the "implements" keyword for this, but maybe we should rather use something else. - Using the trait in a class does NOT automatically add that interface to the class. I personally don't have a strong desire for this functionality. But at least this would circumvent the problems you pointed out. In my personal experience, in all the cases where I did use traits, I would have rather used multiple inheritance. Or let's say: In many cases where I did use traits, or base classes, I did later find a better solution with composition. A good base class, for me, has - private properties - abstract protected methods - possibly final public methods In which cases would I use (single) base classes instead of composition? - If composition would require awkward one-off interfaces. - If the to-be-implemented methods have parameter constraints that cannot be expressed in the signature. E.g. a base class could implement a public method, do some sanity checks and preparation on the parameters, then call the abstract protected method with the processed parameters. In which cases would I use multiple base classes instead of composition or single base classes? - If I want to provide an object with a rich verbose interface to a consumer, possibly extending multiple smaller interfaces. (- If I am implementing someone else's interface, which happens to have more methods than I want to fit in one class.) Base classes allow to implement partial functionality in isolated (encapsulated) pockets of an object. Often each of these pockets is nothing more than a decorator of the partial interface, and the actual functionality happens in the injected object. I would prefer to implement those decorator pockets separately and then extend them one by one. But this is not possible, because we don't have multiple inheritance in PHP. Traits are quite useless for this purpose. They encapsulate nothing. Therefore I don't like them. Sometimes if I started with the assumption that I want to provide a rich one-object interface at least in some places in the architecture, I later regret it, and split it up again. But I do think that some cases are justified. On 1 March 2018 at 01:34, Marco Pivetta wrote: > This cannot work for a number of reasons: > > - a trait is not a type, and does not practically exist at runtime > - trait defined API can be imported with changed/aliased names, breaking > therefore the contact defined in the interface > - due to the previous point, inheriting a type from a trait becomes a > dangerous BC boundary, easily broken by consumers of the trait when > consumers alias or when the trait implementor adds a new interface > implementation > > My general suggestions: > - don't use traits > - don't use traits > - also, don't use traits > - remember to not use traits > - traits: don't > - things you shouldn't use on Betelgeuse and other systems: traits > > Besides jokes, inheriting signatures together with implementations > (inheritance, abstract types) is less and less endorsed in the PHP > ecosystem, as it just increases coupling by a huge lot. At least from my > own experience, things are finally moving towards more composition over > inheritance. > > On 28 Feb 2018 21:58, "David Rodrigues" wrote: > >> Why traits doesn't supports interfaces (via implements) like classes does? >> >> It could be useful when trait implements part of abstract functions from >> interface, then the class that uses this traits should implements the >> another part. >> >> It could turn it possible (pseudo-code): >> >> interface VisibilityControlContract >> - public function isVisible(): bool; >> >> trait VisibilityControlTrait implements VisibilityControlContract >> - public function isVisible(): bool { ... } >> >> class UserModel (not need implements VisibilityControlContract directly) >> - uses VisibilityControlTrait; >> >> var_dump(new UserModel instanceof VisibilityControlContract); // true >> >> The disvantages that I can see with that is that without an IDE I could not >> identify easily if interface was implemented by some trait. But it too >> happen when I do implements an abstract class that implements some >> interface. >> >> -- >> David Rodrigues >>