Are Traits and Inheritance antipatterns in PHP?

Devlob
Devlob
Feb 18 · 4 min read

If you prefer a video version of this post, then you can watch it here: https://devlob.com/courses/design-patterns-in-php-to-solve-real-life-software-problems/antipatterns/traits

Inheritance is very common in OOP languages, however, traits is a unique feature available in PHP that provides multiple inheritance.

Let’s start with inheritance, because if inheritance is bad then traits must be awful!

Before I go through the explanation, I want to be transparent about this post.

I don’t find inheritance a disaster, I just think developers overuse it. Most of the times it is not needed. If I have to use it, then I swap for an abstract class if possible.

In this post, I want to discuss a critical problem that arises with inheritance and traits.

The problem of inheritance

In my course Design Patterns in PHP to Solve real-life Software Problems we used inheritance, but we always extended an abstract class.

Is it bad to extend a class? How bad is it?

Let’s set up a small example to understand the problem behind inheritance.

The class above contains 2 methods, edit, and delete. However, only an admin can call delete. Now let’s create an Editor class that extends Operations.

Because Editor extends Operations we can call the edit method on an editor object.

That’s fine, but because of inheritance, the object also has access to the delete method.

However, this is a huge problem. An editor should not be able to delete a post.

The delete method right now simply has an echo, but imagine that inside that we have more code. Imagine that delete will take some actions, actions that an editor should not be able to take, that will result in errors.

The same issue arises with traits in PHP. Let’s create an AddressTrait.

We will use this trait for Destination and User classes.

The problem, in this case, is that a User should have only 1 address. Destination class is fine. We can set up address 1 and address 2, but a User should have only 1 address.

Because of the way traits work, a user can call setAddress2.

The code above will throw a database error. The table ‘users’ doesn’t have an address2 field and since setAddress2 will update that field on the ‘users’ table, it will throw a database error.

To better understand this problem, imagine the following scenario:

We have Jhon the developer, Alice the project manager and Alex the editor.

Alice — John please hurry, we need this feature deployed in 10 minutes.

Jhon — Ok Alice, just a second “accidentally calls delete instead of edit”

… 10 minutes later …

Alice — Alex you have a typo here, please fix it.

Alex — Ok Alice. “Fixes type and clicks on update”. Guys, I lost the article, I think it got deleted.

If Jhon had used an abstract class instead with an empty body for delete, this would have never happened.

In a nutshell. By using inheritance and traits we get access to methods that shouldn’t be there!

The solution

The solution to this problem is to use abstract classes and interfaces as we did in Design Patterns in PHP to Solve real-life Software Problems.

We solved real-life programming problems and we never extended a class, we always extended an abstract class.

Let’s start with interfaces.

An interface is just a contract. You simply define what methods a class should implement. Methods inside an interface DO NOT have a body!

Let’s now go back to the first example. We will change the Operations class to an interface.

Editor class will implement that interface:

Oh, wait… Do we now have an empty method? Yes, we do! Is that bad? NO!

An empty method that does nothing is better than a method that has code inside and takes some actions and modifies our data.

Alex can edit as usual and if you accidentally call delete on Alex… well, nothing happens! The method is empty!

However, in the case of inheritance, the delete method will have code. Code that can be catastrophic for your application, simply because an editor cannot delete a post and calling delete on an editor will result in errors.

If you prefer an abstract class, then you can have the following.

You can have your usual code inside edit and keep delete empty since it should be implemented only by authorized users.

Conclusion

This post focuses on an important OOP design. You could easily have an if statement inside delete that checks whether a user is an admin, but as I said, we focused on an important OOP design here. Inheritance and traits are an OOP design in PHP that describe how classes communicate together.

If you want to take a look at my course, then you can watch it here Design Patterns in PHP to Solve real-life Software Problems. It is a premium course, but I have some free videos there as well.

Devlob

Written by

Devlob

Making dreams come true...one course at a time!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade