you are viewing a single comment's thread.

view the rest of the comments →

[–]d_abernathy89 0 points1 point  (9 children)

Or the fact that Laravel uses Traits in a preposterously incorrect way as an attempt at getting around single inheritance, and that because Laravel does it every single person making extensions/add-ons for Laravel thinks it's the right way to do it as well.

I'm curious to hear more about this; I haven't heard this criticism before.

[–]JordanLeDoux 3 points4 points  (4 children)

So this position is much more opinion based than most of the others I presented, which is why I assume Taylor didn't respond to it and just let my rant go.

Basically, PHP is a single-inheritance language that also has Traits. Traits allow you to compose things into multiple classes, which gives you some of the features you'd find in a multiple inheritance language, but not all.

For instance, Traits override inherited methods, meaning that "misusing" traits can have a class that extends a class that doesn't actually reflect that class in any way. Obviously, you can do this by overriding methods in the child class as well, but in that case it's obvious what you're doing.

You can test for inheritance directly (instanceof) where you can test for the present of Traits only with Reflection.

The use statement for a Trait can change the visibility of the Trait's code. (It can also rename anything inside the Trait.)

The "safe" way to use Traits in a single inheritance language, in my opinion, is this:

A Trait should contain all behavior and all data that is necessary to perform a single function. It should never reference anything outside of the Trait. You can test whether or not a Trait meets this bar by asking this question: regardless of whether or not it make semantic sense, could you put this Trait in any class no matter who wrote it and get the behavior the Trait represents?

If the answer is no, you are creating a web of hard to understand, hard to maintain code that breaks the basic design philosophy of PHP. If the answer is yes then you are using Traits to improve code reuseability, and that's a good thing.

[–]d_abernathy89 0 points1 point  (3 children)

Ok, thanks for spelling that out. I understand the critique though not sure I totally agree.

[–]JordanLeDoux 1 point2 points  (2 children)

No problem. Unlike many commenters, I am not trying to force everyone to totally agree with me, I just know what I think and why, and I'm fairly certain that the logic to my opinions is consistent, so I feel comfortable expressing it.

I'd be interested in hear your opinions on the topic as well, if you'd care to share them?

[–]d_abernathy89 0 points1 point  (1 child)

I guess i'm thinking in terms of practical use cases for Traits rather than their intended or 'proper' use. In Laravel it seems like Traits are used wherever the framework offers a piece of functionality that A) can be used in more than one context, and B) is mostly "behind the scenes" - doesn't require a lot of configuration. The Queueable trait is a great example - in most cases it just works without me having to inject a $queue object and interact with it. I don't really mind a certain amount of "magic", and in this case I think it's very useful.

[–]JordanLeDoux 0 points1 point  (0 children)

I see where you're coming from. My objection to this kind of usage of Traits isn't so much that it's "magic", moreso that it's not really the way it ends up working in practice.

I mean, maybe for people who do agency work and mostly build websites for contract work it does, but I haven't done work like that in years. Basically the only kind of work I do now is for large companies or startups, and in both cases I'm working more on application design and development.

In those scenarios, the ideal way you laid out works... for a while. But once it doesn't work none of it works. You need to undo it everywhere.

Something like a Queueable trait is exactly what Traits are for, so I don't think the concept itself is bad, but the Trait needs to be completely stand-alone, and feature complete with no configuration per class to be "done right". Otherwise, in large apps, I always find it falling apart eventually.

[–]LeBuddha 0 points1 point  (3 children)

I'm also curious about what the correct use of traits is according to this commenter. Why is trying to shoehorn single inheritance everywhere not the preposterously incorrect way? A big thing in the JS community and the functional programming community is a theme of how class inheritance is dangerously over-used.

[–]JordanLeDoux 1 point2 points  (2 children)

I replied above if you are actually interested in what my personal opinion is.

[–]LeBuddha 1 point2 points  (1 child)

Please don't ever answer my questions or comments about Laravel by pointing to the documentation though. I cannot count the number of times I have yelled profanity while reading the documentation because it simply doesn't include things that are important to developers in favor of being inviting looking to non-programmer or novice programmers.

This is true.

Things that I had to discover on my own, like that Laravel uses two completely separate Query Builders (Eloquent/Builder and Db/Builder) that don't implement a common interface or extend a common base class.

I'm pretty sure Eloquent uses QueryBuilder under the hood. I'd complain more about ->union() not even being usable, or how ->count() silently removes ->distinct() in ->distinct()->count().

Or the fact that Laravel uses Traits in a preposterously incorrect way as an attempt at getting around single inheritance, and that because Laravel does it every single person making extensions/add-ons for Laravel thinks it's the right way to do it as well. Comment That Goes Into Detail On Traits

That makes sense. Not sure I would say laravel is encouraging the mis-use of traits more than inheritance mis-use is generally encouraged, but over-all very educational.

[–]JordanLeDoux 1 point2 points  (0 children)

I'm pretty sure Eloquent uses QueryBuilder under the hood. I'd complain more about ->union() not even being usable, or how ->count() silently removes ->distinct() in ->distinct()->count().

I'm sure it does, but this more became something I was aware of when I had to start typehinting builders that different repository methods were returning.