为什么我们需要检查用户是否是 UserInterface 的实例
Why do we need to check if user is instance of UserInterface
我注意到在 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
的实例?
是的,这对于新老开发者来说有点陌生。
接口允许多重继承。有人告诉我,当 classes 最好被描述为 "is a" 时,你使用继承,就像狗是动物或 SwiftMailer 是邮件程序。
接口然后可以用来插入额外的功能,它就像一个合同,说这个 class 必须实现一些方法。像树皮或邮件。我被告知这些接口应该命名为 canBark 或 Barkable 或 Mailable 等,然后这些接口将实现 bark 或 mail 等方法。
但现代开发更倾向于使用接口作为额外的抽象,因此您可以快速交换 classes。
因此,您可以绑定到用户 class 将实现的用户界面,而不是绑定到您的用户 class。
所以要回答您的实际问题,只要 FOS\UserBundle\Model\User class 或您的用户 class 实现了 UserInterface 接口,那么您就可以开始了。
是的,如果您的代码不是开源的,否则不是。
不检查对象的实例并不能确保通过方法 getUser()
编辑的对象 return 将具有您期望的所有方法(示例:getUsername()
)。
如果您查看 Controller.php 中的 getUser()
方法,它不一定是 return 用户对象。事实上,你可以设置 Symfony2 防火墙 getUser()
return 不同实例的不同对象。
承认我们有一个定义了 getUsername()
.
的接口 UserInterface
在下面的代码中,我们的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;界面是设定期望和避免重大麻烦的好方法。
通读代码后,您可以快速识别传递的对象类型。如果有人更改代码,它要么显示有意义的错误,要么正常降级(在这种情况下,用户将被拒绝访问)。
If my user entity extends FOS\UserBundle\Model\User
, in which case $user
will not be instance of 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
是一个对象,但你不知道对象有哪些 public 方法,等等。没有什么能阻止 $this->getUser()
返回一个完全不同的对象,破坏你的代码。当您检查实例时,您有一个承诺:接口中的方法对您可用。通常,我建议您永远不要调用您没有明确输入提示或检查使用 instanceof
.
的方法
Wouter J 是对的:FOS\UserBundle\Model\User 实现了 FOS\UserBundle\Model\User 接口,但如果您不在文件中附加 "use FOS\UserBundle\Model\UserInterface;",那么 instanceof 测试将不会通过。别忘了。
我注意到在 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
的实例?
是的,这对于新老开发者来说有点陌生。
接口允许多重继承。有人告诉我,当 classes 最好被描述为 "is a" 时,你使用继承,就像狗是动物或 SwiftMailer 是邮件程序。
接口然后可以用来插入额外的功能,它就像一个合同,说这个 class 必须实现一些方法。像树皮或邮件。我被告知这些接口应该命名为 canBark 或 Barkable 或 Mailable 等,然后这些接口将实现 bark 或 mail 等方法。
但现代开发更倾向于使用接口作为额外的抽象,因此您可以快速交换 classes。
因此,您可以绑定到用户 class 将实现的用户界面,而不是绑定到您的用户 class。
所以要回答您的实际问题,只要 FOS\UserBundle\Model\User class 或您的用户 class 实现了 UserInterface 接口,那么您就可以开始了。
是的,如果您的代码不是开源的,否则不是。
不检查对象的实例并不能确保通过方法 getUser()
编辑的对象 return 将具有您期望的所有方法(示例:getUsername()
)。
如果您查看 Controller.php 中的 getUser()
方法,它不一定是 return 用户对象。事实上,你可以设置 Symfony2 防火墙 getUser()
return 不同实例的不同对象。
承认我们有一个定义了 getUsername()
.
UserInterface
在下面的代码中,我们的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;界面是设定期望和避免重大麻烦的好方法。
通读代码后,您可以快速识别传递的对象类型。如果有人更改代码,它要么显示有意义的错误,要么正常降级(在这种情况下,用户将被拒绝访问)。
If my user entity extends
FOS\UserBundle\Model\User
, in which case$user
will not be instance ofUserInterface
?
这不是真的,因为 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
是一个对象,但你不知道对象有哪些 public 方法,等等。没有什么能阻止 $this->getUser()
返回一个完全不同的对象,破坏你的代码。当您检查实例时,您有一个承诺:接口中的方法对您可用。通常,我建议您永远不要调用您没有明确输入提示或检查使用 instanceof
.
Wouter J 是对的:FOS\UserBundle\Model\User 实现了 FOS\UserBundle\Model\User 接口,但如果您不在文件中附加 "use FOS\UserBundle\Model\UserInterface;",那么 instanceof 测试将不会通过。别忘了。