> 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 <ocramius@gmail.com> wrote: