Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the Laravel trait pattern?

Tags:

While looking at the Laravel source, I noticed a lot of stuff like this:

A controller class:

class Controller extends BaseController
{
    use AuthorizesRequests, AuthorizesResources, DispatchesJobs, ValidatesRequests;
}

One of its component traits:

trait AuthorizesRequests {

    /**
     * Authorize a given action against a set of arguments.
     *
     * @param  mixed $ability
     * @param  mixed|array $arguments
     *
     * @return \Illuminate\Auth\Access\Response
     *
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function authorize($ability, $arguments = []) {
        list($ability, $arguments) = $this->parseAbilityAndArguments($ability, $arguments);
        return app(Gate::class)->authorize($ability, $arguments);
    }

    // ...

}

I have a couple of questions about this:

  • Does this pattern (abstracting re-usable functionality into traits) have a name?
  • Is this pattern used to good effect in any other projects?
  • If a trait requires dependencies, is there a best-practise way to inject them, instead of using a service locator (like app(), in this case)?

I'm considering using this approach in my code to share some general functionality between a couple of my classes - I'm considering creating a ChecksBarcodes trait, which will work with a repository of stock information, and sharing that trait between a few similar but unrelated product management process classes, which all need to check barcodes.

like image 832
Alex Avatar asked Jun 22 '16 10:06

Alex


2 Answers

Traits, being introduced with PHP 5.4, in general solving one big problem of PHP: single inheritance. A rough guess from me: if PHP would support multi inheritance (inherit from more than one class) there wouldn't be traits.

Nevertheless, traits are a good thing to reduce duplications of code and furthermore provide same fuctionality to multiple classes.

  • As far as I can see, there is no real (pattern) name for using traits.
  • It is not a pattern per se, as compared to other Software design pattern, just call it traits ;)
  • Laravel and maybe more specifically the Cashier package are good examples of using traits. If somebody finds other good examples please mention it.
  • Traits can be extended by other traits. That of course creates more and more complexity. To extend you probably should consider other methods to bring a functionality to your class. "Chaining" of traits adds load of complexity.
like image 58
codedge Avatar answered Oct 06 '22 00:10

codedge


Traits are similar to extending classes, but with a few differences

  • Traits don't have a constructor
  • Classes can only extend one class, but have multiple traits

They're similar to mixins in other languages. I guess you could say its an easy way to use the DRY principle.

Since traits don't have constructors, any dependencies they have would need to exist on the class they're used on. I think depending on the class to have something other than the trait would be a bad design pattern. So you would have to use a service locator to pull in dependencies.

If you would rather not use a service locator, I would recommend using a class rather than a trait. You could have a BarcodeChecker class that you could inject into the constructor of the classes you want to use it. Then instead of $this->checkBarcode() you would use $this->barcodeChecker->check(). I think that would be a better design pattern if the trait requires dependencies.

like image 34
Jeff Avatar answered Oct 06 '22 02:10

Jeff