为什么我们需要检查用户是否是UserInterface的实例

时间:2015-05-14 18:45:47

标签: php symfony fosuserbundle

我已在FOSUserBundle控制器(ProfileController)中注意到$userUserInteface的实例

的检查
$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的实例?

4 个答案:

答案 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测试将不会通过。别忘了。