189

Given a class instance, is it possible to determine if it implements a particular interface? As far as I know, there isn't a built-in function to do this directly. What options do I have (if any)?

Wilco
  • 32,754
  • 49
  • 128
  • 160

6 Answers6

312
interface IInterface
{
}

class TheClass implements IInterface
{
}

$cls = new TheClass();
if ($cls instanceof IInterface) {
    echo "yes";
}

You can use the "instanceof" operator. To use it, the left operand is a class instance and the right operand is an interface. It returns true if the object implements a particular interface.

Reference: https://www.php.net/manual/en/language.operators.type.php#example-124

nanocv
  • 2,227
  • 2
  • 14
  • 27
  • Note that, this won't be useful if you are trying to determine constructor of the class – AaA Nov 23 '20 at 08:12
128

As therefromhere points out, you can use class_implements(). Just as with Reflection, this allows you to specify the class name as a string and doesn't require an instance of the class:

interface IInterface
{
}

class TheClass implements IInterface
{
}

$interfaces = class_implements('TheClass');

if (isset($interfaces['IInterface'])) {
    echo "Yes!";
}

class_implements() is part of the SPL extension.

See: http://php.net/manual/en/function.class-implements.php

Performance Tests

Some simple performance tests show the costs of each approach:

Given an instance of an object

Object construction outside the loop (100,000 iterations)
 ____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 140 ms           | 290 ms     | 35 ms      |
'--------------------------------------------'

Object construction inside the loop (100,000 iterations)
 ____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 182 ms           | 340 ms     | 83 ms      | Cheap Constructor
| 431 ms           | 607 ms     | 338 ms     | Expensive Constructor
'--------------------------------------------'

Given only a class name

100,000 iterations
 ____________________________________________
| class_implements | Reflection | instanceOf |
|------------------|------------|------------|
| 149 ms           | 295 ms     | N/A        |
'--------------------------------------------'

Where the expensive __construct() is:

public function __construct() {
    $tmp = array(
        'foo' => 'bar',
        'this' => 'that'
    );  

    $in = in_array('those', $tmp);
}

These tests are based on this simple code.

Community
  • 1
  • 1
Jess Telford
  • 12,880
  • 8
  • 42
  • 51
62

nlaq points out that instanceof can be used to test if the object is an instance of a class that implements an interface.

But instanceof doesn't distinguish between a class type and an interface. You don't know if the object is a class that happens to be called IInterface.

You can also use the reflection API in PHP to test this more specifically:

$class = new ReflectionClass('TheClass');
if ($class->implementsInterface('IInterface'))
{
  print "Yep!\n";
}

See http://php.net/manual/en/book.reflection.php

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
27

Just to help future searches is_subclass_of is also a good variant (for PHP 5.3.7+):

if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
    echo 'I can do it!';
}
d.raev
  • 9,216
  • 8
  • 58
  • 79
26

Update

The is_a function is missing here as alternative.

I did some performance tests to check which of the stated ways is the most performant.

Results over 100k iterations

      instanceof [object] took   7.67 ms | +  0% | ..........
            is_a [object] took  12.30 ms | + 60% | ................
             is_a [class] took  17.43 ms | +127% | ......................
class_implements [object] took  28.37 ms | +270% | ....................................
       reflection [class] took  34.17 ms | +346% | ............................................

Added some dots to actually "feel" see the difference.

Generated by this: https://3v4l.org/8Cog7

Conclusion

In case you have an object to check, use instanceof like mentioned in the accepted answer.

In case you have a class to check, use is_a.

Bonus

Given the case you want to instantiate a class based on an interface you require it to have, it is more preformant to use is_a. There is only one exception - when the constructor is empty.

Example: is_a(<className>, <interfaceName>, true);

It will return bool. The third parameter "allow_string" allows it to check class names without instantiating the class.

apaderno
  • 28,547
  • 16
  • 75
  • 90
SirPilan
  • 4,649
  • 2
  • 13
  • 26
5

You can also do the following

public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
   //.....
}

It will throw an recoverable error if the $objectSupposedToBeImplementing does not implement YourInterface Interface.

Starx
  • 77,474
  • 47
  • 185
  • 261