Why do we need to check if the user is an instance of UserInterface

I noticed in FOSUserBundle ( ProfileController ) controllers check if an $user

instance isUserInteface

$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
    throw new AccessDeniedException('This user does not have access to this section.');
}

      

Is it enough to check only if (!is_object($user))

?

If my custom object extends FOS\UserBundle\Model\User

, in this case, $user

would it not be an instance UserInterface

?

+3


source to share


4 answers


Yes, unless your code is open-source, otherwise no.

Not checking an instance of an object does not guarantee that the object returned by a method getUser()

will have all the methods you expect (example:) getUsername()

.

If you look at the getUser()

Controller.php method , it doesn't necessarily return a user object. In fact, you can configure the Symfony2 firewall to getUser()

return a different object of a different instance.

Let's admit that we have an interface UserInterface

that defines getUsername()

.

In the following code, our custom object does not implement UserInterface

.

$user = $this->getUser();
if (!is_object($user)) {
    $user->getUsername();
}

      

This code throws an error because it getUsername()

doesn't exist on the object, instead the code should be like this:

$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
    $user->getUsername();
}

      



If the custom object does not implement the correct interface then the code will not crash because it will not be executed.

Avoid checking the object like this

$user = $this->getUser();
if (!is_object($user) || !$user instanceof User) {
    $user->getRoles();
}

      

If someone extends the User object, then the if statement will no longer be executed because it $user

won't be an instance User

, but will say ExtendedUser

although it has all the required methods.

Another advantage of using interfaces is that you can implement multiple interfaces for an object.

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 the key:
                  //        both A and B implements C but B is not an
                  //        instance of A.
$nB instanceof D; // true - A implements D

      

TL; DR; interfaces are a great way to set expectations and avoid major headaches.

As you read the code, you can quickly identify the type of objects being passed. If someone changes the code, it will either show a meaningful error or it will degrade gracefully (in which case the user will be denied access).

+1


source


If my custom object extends FOS\UserBundle\Model\User

, in this case, $user

would it not be an instance UserInterface

?

This is incorrect because it FOS\UserBundle\Model\User

implements FOS\UserBundle\Model\UserInterface

, which extends (interfaces extend other interfaces) Symfony\Component\Security\Core\User\AdvancedUserInterface

, which extends Symfony\Component\Security\Core\User\UserInterface

. Thus, it $user instanceof UserInterface

will be true.



An interface is a contract in the object-oriented world. With is_object($user)

you know what $user

is an object, but you don't know which public methods the object has, etc. Nothing prevents you from $this->getUser()

returning a completely different object, breaking your code. When you check on an instance, you have a promise: the methods in the interface are available to you. As a general rule of thumb, I would recommend that you never call methods in which you have not explicitly entered text or verified usage instanceof

.

+1


source


Yes, this is a little strange for new and old developers.

the interface allows multiple inheritance. I was taught that you use inheritance when classes are best described as "is," for example, a dog is an animal, or SwiftMailer is a Mailer.

Interfaces

can then be used for additional functionality, they act like a contract that says this class must implement some method. like bark or mail. And I was taught that these interfaces should be called things like canBark or Barkable or Mailable, etc., then they will implement methods like bark or mail.

but modern developers tend to use interfaces as an additional abstraction, so you can quickly change the classes around.

so instead of binding to your custom class, you bind to UserInterface, which will be implemented by the User class.

to answer your real question, if only the FOS \ UserBundle \ Model \ User class or your UI implements the UserInterface, then you're good to go.

-1


source


Wouter J is right: FOS \ UserBundle \ Model \ User implements FOS \ UserBundle \ Model \ UserInterface, but if you don't add "use FOS \ UserBundle \ Model \ UserInterface;" in your file the instanceof test will fail. Don't forget this.

-1


source







All Articles