我在Stackeexchange上看到了一个例子(请注意访问类属性的特性):
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");
}
}
}
阅读回复者的评论:
那么,你的特征就不是一个有效的用例:它的所有用户都是根据定义,需要将$this->容器属性添加到其依赖项,这当然会对该类产生影响合同及其子女的合同。
为什么作者声称这是一个糟糕的用例,如果这可能是某人所需要的?比如,如果有人有几个类都具有所需的依赖关系,并且所有类中都有相同的逻辑记录,那么他们应该保持代码重复吗?
确实,以这种方式使用了trait-这是个坏主意。如果有人决定在你的代码中使用这个特性,他必须确保"容器"属性的存在。"container"应该是正确的类型(包括所使用的方法),否则会出错。事实上,这段代码是不能重复使用的,这可能会导致错误。此外,它违反了SOLID规则的规则DIP(依赖反转原理)。
有可能绕过这个:
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;
}
或者像这样(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;
}
}
我同意这一点,我不认为traits应该使用类的任何方法或属性,但当我阅读laravel框架的源代码时,我看到了许多这种traits的滥用,例如,InteractiveWithInput trait与请求类深度耦合,这让非常困惑
trait InteractsWithInput
{
//the getInputSource method is defined in Request class
public function input($key = null, $default = null)
{
return data_get(
$this->getInputSource()->all() + $this->query->all(), $key, $default
);
}
}
class Request
{
use InteractsWithInput
protected function getInputSource()
{
if ($this->isJson()) {
return $this->json();
}
return in_array($this->getRealMethod(), ['GET', 'HEAD']) ? $this->query : $this->request;
}
}