PHP instanceof Operator Tips

26th January 2021 - 8 minutes read time

The instanceof operator in PHP is great at making sure you are looking at a type of object before acting on it. Whilst it's straightforward to use on its own, using it can lead to some undesirable side effects.

As a basic example, let's create a couple of interfaces and classes to show the instanceof operator in action. Rather than just have some test names I am using object names that you might find in a system. This consists of User and Order that might form part of a commerce system.

  1. interface UserInterface {}
  2. class User implements UserInterface {}
  4. interface OrderInterface {}
  5. class Order implements OrderInterface {}

If we instantiate the User object we can detect if the user is an instance of the class User like this.

  1. $user = new User();
  2. var_dump($user instanceof User); // Returns true

As the User object implements an interface we can also detect if the User object is an instance of an interface like this.

var_dump($user instanceof UserInterface); // Returns true

Conversely, if we were to see if the $user variable we created is an instance of a different kind of object then it would return false, like this.

var_dump($user instanceof Order); // Returns false

If we aren't sure what kind of interface or object we are going to receive then we can pass in a variable that contains the name of the interface.

  1. $interface = 'UserInterface';
  2. var_dump($user instanceof $interface);

Note that just passing in the interface as a string, as in the following snippet, will produce a syntax error. The item you use to detect the type of object or interface must be either a variable or a fully qualified class or interface name.

  1. var_dump($user instanceof 'UserInterface');
  2. // PHP Parse error: syntax error, unexpected ''UserInterface'' (T_CONSTANT_ENCAPSED_STRING) in index.php on line 2

Negating the instance of operator is a little less straightforward, but can be done by putting an exclamation mark at the beginning of the statement.

var_dump(!$user instanceof UserInterface); // Returns false

It is usually good practice to wrap the whole thing in brackets so that you can be sure of the outcome of the check.

var_dump(!($user instanceof UserInterface)); // Returns false

You can also compare the output of the instanceof operator to false, which essentially negates it. I find this a little more difficult to read, although you could also argue that you might miss the exclamation mark.

var_dump(FALSE === $user instanceof UserInterface); // Returns false

When namespaces are involved then care must be taken that the right syntax is used. When using the fully qualified namespace then the proceeding slash is required, otherwise the right instance won't be found. It's probably best practice to not use the fully qualified namespace at all though and just to rely on the interface name you are looking for. The following example is looking at a Drupal interface called FormStateInterface with three different ways of writing down the class name.

  1. use Drupal\Core\Form\FormStateInterface;
  3. var_dump($form_state instanceof Drupal\Core\Form\FormStateInterface); // returns false
  4. var_dump($form_state instanceof \Drupal\Core\Form\FormStateInterface); // returns true
  5. var_dump($form_state instanceof FormStateInterface); // returns true

A single instanceof check is easy enough to understand, but if you are trying to detect if an object is one of a series of types of objects then the code gets a little difficult to read. For example, let's say that you are trying to detect if an object was one of a series of the three types of interface defined at the beginning of the post; you might create an if statement like the following.

  1. var_dump($object instanceof UserInterface || $object instanceof ProductInterface || $object instanceof OrderInterface); // returns true

This returns true, which indicates that the object is one of the instance types we are looking for.

I found a good function that allows this to be encapsulated neatly whilst reading stack overflow the other day (see the original stack overflow comment here). To detect if an object is one of a series of types you can use the following function that will take an object and an array of classnames.

  1. function isInstanceOf($object, Array $classnames) {
  2. foreach($classnames as $classname) {
  3. if($object instanceof $classname){
  4. return true;
  5. }
  6. }
  7. return false;
  8. }

This can be run in the following way. Passing in the previously created user object and an array that contains the instance types we are looking for as strings returns true.

var_dump(isInstanceOf($user, ['UserInterface', 'ProductInterface', 'OrderInterface'])); // Returns true

The instanceof operator will also work for child objects. Take the following code that creates an interface, defines a User class and then defines an Administrator class that extends the User class.

  1. interface UserInterface {}
  2. class User implements UserInterface {}
  3. class Administrator extends User {}

We can instantiate the User and Administrator objects and try to detect them in different ways. 

  1. $user = new User();
  2. $administrator = new Administrator();
  4. var_dump($user instanceof UserInterface); // Returns true
  5. var_dump($user instanceof User); // Returns true
  6. var_dump($user instanceof Administrator); // Returns false
  8. var_dump($administrator instanceof UserInterface); // Returns true
  9. var_dump($administrator instanceof User); // Returns true
  10. var_dump($administrator instanceof Administrator); // Returns true

The thing to note from the above code is that a User object is not an instance of an Administrator object and so that comparison returns false. The Administrator object is, however, an instance of the User object and so that comparison is true.

What happens then, if we are trying to detect the instance of just an Administrator object, and not a User object. Unfortunately the instanceof operator can't be used here. Instead, in order to detect just the one type of class you are looking for you'll need to use a different comparison using the get_class() PHP method.

  1. var_dump(get_class($administrator) === 'Administrator'); // returns true
  2. var_dump(get_class($user) === 'Administrator'); // returns false

Note that the User object is not an Administrator object and so the comparison returns false. The above can also be written differently using the ::class magic constant to return the string of the class name. This is actually the way I normally print out class names and the way I would write this type of comparison.

  1. var_dump(get_class($administrator) === Administrator::class); // returns true
  2. var_dump(get_class($user) === Administrator::class); // returns false

Ultimately, the instanceof operator is useful, but you need to follow these rules to get the most out of it.

  • When detecting a type of object try as much as possible to detect the instance, rather than the class. This allows for good SOLID principles to be followed.
  • Don't use the fully qualified name of the interface. Using just the interface name is sufficient and follows best practice.
  • If looking for the absence of an instance then be sure to wrap the comparison in brackets to avoid any inconsistencies in the precedence of surrounding operators.
  • Be careful when using inheritance, all objects inheriting a parent class will be detected as being the same type as the parent.

Add new comment

The content of this field is kept private and will not be shown publicly.