On a recent episode of the The Midwest Artisan podcast, Andy and I talked about a recent "issue" I was running into:
dynamically including a Trait in a class based on a conditional.
The Problem
The problem is that trying to include a Trait of methods into a class at runtime is not simple, nor is it really useful in 99% of use cases. But, I had a very, very niche use case where I wanted to check if a certain composer package was installed and, if it was, include that package's Trait.
Seems simple enough, right? Well... it wasn't. And it took me a while to figure out how to do it. But, I ended up with a solution I was happy with and that worked.
Now, I know developer opinions can run wild with a topic like this...
"Why are you doing this? You shouldn't be doing this."
"What if the package isn't installed and you try called a method that isn't available?"
"Could you use something else like an Interface or extend another class?"
I get it though. I understand the concerns and the potential issues that could arise from this. But, the applications I am building with this are all my own and I wanted to have a reusable package that I could use in multiple projects with the least amount of set up and configuration. I.e. install the package and "it just works." Sound familiar? Cough, cough, Laravel.
The Solution
So here is how I solved this problem. I made a wrapper Trait that would have a conditional check to see if a config value was set, based on the installed package. If the config value was set, I would include the package's Trait. If not, I would just return an empty Trait class with no methods. It ended up looking something like this:
// WrapperTrait.php
if (config('my-package.enabled')) {
trait WrapperTrait {
use PackageTrait;
}
} else {
trait WrapperTrait {}
}
// MyClass.php
class MyClass
{
use WrapperTrait;
}
Yeah, it's not elegant, and PHPStorm complains a lot about that `WrapperTrait.php` file, but it works. Let me know your thoughts or if you have a better solution! I would love to hear it. Shoot me a message on X/Twitter: @DaltonMcCleery
You can listen to this episode here or below!