Is a class dependency access property a bad idea?

I saw an example in Stackexchange (note the sign, access to the class property):

trait CheckPermissionTrait { protected function checkPermission($object_id) { $judge = $this->container->get('acme_judge'); $user = $this->container->get('security.context')->getToken()->getUser(); if( !$judge->isPermitted($user, $object_id) ) { throw $this->createAccessDeniedException("Brabbel"); } } } 

And read one of the comments:

Your trait, then, is not an acceptable precedent: all its users are required, by definition, to add the $ this-> container property to their dependencies, which, of course, will affect this class of the contract and the contract of his children.

Why does the author claim that this is a bad use case, if it can be what someone needs? For example, if someone has several classes, all of which have the necessary dependency and the same logical replication in all of them, should they just duplicate the code?

+6
source share
1 answer

Indeed, the trait used in this way is a bad idea. If someone decides to use this trait in your code, they must ensure that the container attribute exists. the "container" must be correct (including the methods used), otherwise it will get an error. In fact, this code cannot be reused, and this is potentially a mistake. In addition, it violates the DIP rule (dependency inversion principle) of SOLID rules.

You can get around this:

 interface ExampleContainerInterface{ } trait CheckPermissionTrait { protected $container; public function __construct(ExampleContainerInterface $container) { $this->container = $container; } protected function checkPermission($object_id) { $judge = $this->container->get('acme_judge'); $user = $this->container->get('security.context')->getToken()->getUser(); if( !$judge->isPermitted($user, $object_id) ) { throw $this->createAccessDeniedException("Brabbel"); } } } class ExampleClassA { use CheckPermissionTrait; } class ExampleClassB { use CheckPermissionTrait; } 

or like this (php7):

 interface ExampleContainerInterface{ } trait CheckPermissionTrait { abstract public function getContainer():ExampleContainerInterface; protected function checkPermission($object_id) { $container = $this->getContainer(); $judge = $container->get('acme_judge'); $user = $container->get('security.context')->getToken()->getUser(); if( !$judge->isPermitted($user, $object_id) ) { throw $this->createAccessDeniedException("Brabbel"); } } } class ExampleClassA { use CheckPermissionTrait; protected $container; public function getContainer():ExampleContainerInterface { return $this->container; } } class ExampleClassB { use CheckPermissionTrait; protected $container; public function getContainer():ExampleContainerInterface { return $this->container; } } 
+1
source

All Articles