Traits are not inherited
Tags: webdev, php, tutorial
Published: 2021-08-28 09:56:41

---
description: Traits are not inherited, but copy-pasted. What does that imply?
---

I recently saw this tweet by [Jess Archer](https://jessarcher.com), which showed some `Trait` behavior that might not make sense at first glance. I thought it could be fun to explain why this happens.

{% twitter 1429970207871623176 %}

While saying `Enableable` is cool and all; how in the world is it possible that the `TimeCircuits::$enabled` variable is still `false`, when it was clearly updated on the `Enableable` trait? The answer is: a trait is not inherited.

## Single Inheritance vs. composition

PHP is a so called [Single Inheritance language](https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)#Types) meaning any `class` can inherit context from only **one** parent. In most cases this works out fine, but sometimes you have code in a class you want to re-use. This is impossible if the class you want to use this on already `extends` another class. This is why PHP introduced *traits*.

A trait is a kind of mini-class that can be used inside multiple classes. It can have methods, parameters, static methods and static variables, just like a class. Even the visibility like `private`, `protected` and `public` works the same. But instead inheriting from these traits by using `extends`, you have to `use` the trait inside a class. You actually **have** to `use` a trait inside a class, because you cannot instantiate it on its own. A class can also `use` multiple traits. This way you compose a new class made up of small re-usable pieces of code.

## Traits are copy-pasted

While a trait looks like any other class, this `use`-ing instead of extending makes a big difference. When you `use` a trait, the *current* state of the trait is *copied* to the class. And this copying is the reason why `TimeCircuits` is unaffected by the change on the `Enableable` trait. It is not inheriting this variable; it has it's *own* copy of it. And because the parameter was set to `true` before the `FluxCapacitor` class was created, this class has a copy of *that* state. Resetting `Enableable::$enabled` to `false` at the end will therefore still have no impact on either `TimeCircuits` or `FluxCapacitor`. They are completely separate parameters.

## Classes inherit

So let's see how a class would react to a similar situation. We'll create a `Base` class that has a `static $enabled` parameter, and an `Extended` class that `extends` (and therefore inherits from) `Base`. Then check out what happens when we change the value of this variable.

```php
class Base {
    public static $enabled = false;
}

class Extended extends Base {
}

Base::$enabled = true;

var_dump(Base::$enabled, Extended::$enabled); // (bool) true, (bool) true
```

So here you see the inheritance in action. When we update the parameter on the `Base` class, it's extending classes are affected by this update, because they are actually referencing the same parameter, and *not* a copy. And to prove that they are referencing the same parameter you can change `Extended::$enabled` to `true` *instead* of `Base::$enabled` and the result will still be the same.

## Final notes

I'm not sure if Jess wanted a way to enable all classes that used this trait at the same time. If that is the case, I see 2 alternatives:

1. Let those classes extend from an intermediate class that has this parameter: for example a `Model` could extend a `EnableableModel` that has this parameter. In that case you could update `EnableableModel::$enabled`.
2. Register an interface on all the classes that use this trait, and put them in a container. Then retrieve all classes from the container that have this interface, and update every one separately.

> You might also be interested in my blog post on [Testing Traits in PHPUnit](https://doeken.org/blog/testing-traits-in-phpunit). In this post I'll show you some handy tips and tricks for testing traits.

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>