Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency injection in PHP traits

Do traits actually work with dependency injection? Consider the following code:

Trait Class

namespace Frame\Slick\Block;
use Frame\Slider\Slick\Block\Data as Helper

trait Slick
{
   protected $_slickHelper;
   public function __construct(Helper $slickHelper) 
   {
     $this->_slickHelper = $slickHelper;
   }
}

Class using the trait

namespace Frame\Slick\Block;

class Product ListProduct implements BlockInterface 
{
   use Slick;
   public function testTrait()
   {
      return $this->_slickHelper->getHelloWorld();
   }
}

This seems to always return null, am very sure everything is being included properly. Can trait really support dependency injection?

like image 999
André Ferraz Avatar asked Aug 10 '16 15:08

André Ferraz


People also ask

What is PHP dependency injection?

Dependency injection is a procedure where one object supplies the dependencies of another object. Dependency Injection is a software design approach that allows avoiding hard-coding dependencies and makes it possible to change the dependencies both at runtime and compile time.

What are the traits in PHP?

Traits are used to declare methods that can be used in multiple classes. Traits can have methods and abstract methods that can be used in multiple classes, and the methods can have any access modifier (public, private, or protected).

What are the advantages of dependency injection in PHP?

This provides a developer with the freedom to create a computer object with different components without having to extend classes and override constructors.

Can a trait have a constructor PHP?

Unlike traits in Scala, traits in PHP can have a constructor but it must be declared public (an error will be thrown if is private or protected). Anyway, be cautious when using constructors in traits, though, because it may lead to unintended collisions in the composing classes.


2 Answers

Yes they work the code from trait is "pasted" on compliation level. Consider the following code. It works as expected and echos proper value. Your problem is elsewhere.

<?php
class Dependency
{
    public function foo()
    {
        return 'test';
    }
}

trait Slick
{
   protected $dep;

   public function __construct(Dependency $dep) 
   {
       $this->dep = $dep;
   }
}

class Product 
{
   use Slick;

   public function testTrait()
   {
      return $this->dep->foo();
   }
}

echo (new Product(new Dependency()))->testTrait();

The code will echo 'test'. Working fiddle

like image 185
Robert Avatar answered Oct 01 '22 18:10

Robert


A properly implemented framework should be able to do dependency injection on trait constructors. Typically parameters which are eligible for injection are determined using reflection. Consider the following example:

<?php 

class D {}

trait T {

    public function __construct(D $d) { }


}

class A {

use T;

}


$cls = new ReflectionClass("A");

$ctor = $cls->getConstructor();

print_r($ctor->getParameters()[0]->getClass());

Prints:

ReflectionClass Object
(
    [name] => D
)

This indicates that the framework can use reflection to determine whether or not to inject the dependency, the fact that the constructor is in the trait does not matter.

If this is not happening in magento then I suggest you move this to their suggestion thread (if any).

I would also recommend you read up on how dependency injection works in magento via their dependency injection documentation

like image 37
apokryfos Avatar answered Oct 01 '22 16:10

apokryfos