我已在FOSUserBundle控制器(ProfileController)中注意到$user
是UserInteface
的实例
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
仅检查if (!is_object($user))
是否足够?
如果我的用户实体扩展FOS\UserBundle\Model\User
,那么$user
将不是UserInterface
的实例?
答案 0 :(得分:1)
是的,如果您的代码不是开源的,否则不是。
不检查对象的实例并不能确保方法getUser()
返回的对象具有您期望的所有方法(例如:getUsername()
)。 / p>
如果从Controller.php查看getUser()
方法,则不一定会返回用户对象。实际上,您可以以getUser()
将返回不同实例的不同对象的方式设置Symfony2防火墙。
承认我们有一个定义UserInterface
的接口getUsername()
。
在以下代码中,我们的User对象未实现UserInterface
。
$user = $this->getUser();
if (!is_object($user)) {
$user->getUsername();
}
此代码会抛出错误,因为对象上不存在getUsername()
,而代码应该是以下内容:
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
$user->getUsername();
}
如果用户对象没有实现正确的接口,那么代码就会因为不能执行而失败。
避免检查对象,如下所示
$user = $this->getUser();
if (!is_object($user) || !$user instanceof User) {
$user->getRoles();
}
如果某人扩展了User对象,那么if语句将不再被执行,因为$user
将不是User
的实例,而是ExtendedUser
,即使它已全部你需要的方法。
使用接口的另一个好处是可以在对象上实现多个接口。
class A implements C {}
class B extends A implements C, D {}
interface C {}
interface D {}
$nA = new A();
$nB = new B();
$nA instanceof A; // true - instance of A
$nA instanceof B; // false - pretty obvious, no relationship with B
$nA instanceof C; // true - A implements C
$nA instanceof D; // false - A does not implement D
$nB instanceof A; // false - B is not an instance of A
$nB instanceof B; // true - instance of B
$nB instanceof C; // true - A implements C, that's the key:
// both A and B implements C but B is not an
// instance of A.
$nB instanceof D; // true - A implements D
TLDR;接口是设定期望和避免重大麻烦的好方法。
当您阅读代码时,您可以快速识别传递的对象类型。如果有人更改了代码,它将显示有意义的错误,或者它会正常降级(在这种情况下,将拒绝用户访问)。
答案 1 :(得分:1)
如果我的用户实体扩展
FOS\UserBundle\Model\User
,那么$user
将不是UserInterface
的实例?
事实并非如此,因为FOS\UserBundle\Model\User
实现了FOS\UserBundle\Model\UserInterface
,它扩展了(接口扩展其他接口)Symfony\Component\Security\Core\User\AdvancedUserInterface
,扩展了Symfony\Component\Security\Core\User\UserInterface
。所以$user instanceof UserInterface
将是真的。
接口是面向对象世界中的契约。使用is_object($user)
,您知道$user
是一个对象,但您不知道该对象具有哪些公共方法等。没有什么能阻止$this->getUser()
返回完全不同的对象,打破你的代码。检查实例时,您有一个承诺:界面中的方法可供您使用。作为一项规则,我建议您永远不要调用您没有明确键入或使用instanceof
检查的方法。
答案 2 :(得分:-1)
是的,这对新老开发者来说有点奇怪。
接口允许多重继承。我被告知你使用继承,因为当最好地描述类时,"是#34 ;,就像狗是动物或SwiftMailer是梅勒。
然后可以使用接口来增加额外的功能,它就像一个合同,表明这个类必须实现一些方法。像树皮或邮件。我被告知这些接口应该被命名为canBark或Barkable或Mailable等,然后这些接口将实现像bark或mail这样的方法。
但现代开发人员更倾向于使用接口作为额外的抽象,因此您可以快速交换类。
因此,不是绑定到您的用户类,而是绑定到User类将实现的UserInterface。
所以要回答你的实际问题,只要FOS \ UserBundle \ Model \ User类或你的User类实现了UserInterface接口,那么你就可以了。
答案 3 :(得分:-1)
Wouter J是对的:FOS \ UserBundle \ Model \ User实现了FOS \ UserBundle \ Model \ UserInterface但是如果你没有追加"请使用FOS \ UserBundle \ Model \ UserInterface;"在您的文件中,instanceof测试将不会通过。别忘了。