3

I need to check whether a certain class extends or implements a particular interface.

Note that the class name is a variable string, ie, there won't be any instance of this class.

Users are supposed to select a class from a list of classes and the system is supposed to check whether the class implements a certain interface or not. The list of classes is variable (according to the PHP software currently running), some of these classes can be initialized and others cannot.

Here's the code I'm using:

function is_instance_of($obj,$cls){
    if(is_string($obj))$obj=new $obj();
    if(PHP_MAJOR_VERSION>4)return $obj instanceof $cls;
    if(PHP_MAJOR_VERSION>3)return is_a($obj,strtolower($cls));
    return false;
}

var_dump(is_instance_of('MyClass','IMyInterface')); // in theory, true
var_dump(is_instance_of('Closure','IMyInterface')); // FATAL ERROR

That last test shows up the following error:

Catchable fatal error: Instantiation of 'Closure' is not allowed in C:\Users\abcdefghijklmn\debug.php on line XX

Things I tried:

  • Using $obj=new @$obj(); :- error is hidden but it still faults/dies.
  • Using try{}catch(){} around offending block :- nothing different happens
  • Using 'class' instanceof 'class' (where $obj is a string) :- returns false unconditionally

Please note that the mandatory class initialization used in this method...sucks. Creating instances means unnecessary memory consumption, loss in speed and more prone to errors (imagine some weirdo class that when instantiated without parameters it proceeds to destroy your HDD ;) ). So, if there's any other way, I'd simply love to know about it.


Edit: This is (hopefully) the final code:-

/**
 * Cross-version instanceof replacement.
 * @param object $obj The instance to check.
 * @param stirng $cls The class/interface name to look for.
 * @return boolean Whether an object extends or implements a particular class
 *     or interface.
 * @link http://stackoverflow.com/questions/4365567/php-instanceof-over-strings-and-non-initializable-classes
 */
function is_instance_of($obj,$cls){
    if(is_string($obj) || PHP_MAJOR_VERSION>4){
        $rc=new ReflectionClass($obj);
        return $rc->implementsInterface($cls);
    }else{
        if(PHP_MAJOR_VERSION>3)return is_a($obj,strtolower($cls));
        return false;
    }
}
2
  • 1
    As a side note, won't this line cause a parsing error on PHP versions < 5? if(PHP_MAJOR_VERSION>4)return $obj instanceof $cls; The conditional will prevent execution on PHP 4 and less, but the parser will still have to parse it... and I don't think it will be very happy about it. Commented Dec 6, 2010 at 10:55
  • Good point. I'm not sure about that. Any ideas to fix it? I could use good ol' eval ;) :D Commented Dec 6, 2010 at 10:58

2 Answers 2

2

Try using PHP's ReflectionClass instead, e.g.

$rc = new ReflectionClass($obj);
return $rc->implementsInterface($cls);
Sign up to request clarification or add additional context in comments.

3 Comments

I'd prefer a different approach, but this is certainly a good option.
Editing; ReflectionClass seems to behave fine when given an object, so it's even easier.
Actually, I'm not sure which PHP versions ReflectionClass is available for, so if you need to maintain compatibility for PHP < 5, it may not be an option.
0

Use the ReflectionClass:

function is_instance_of($obj,$cls){
    $ref=new ReflectionClass($obj);
    return in_array($cls, array_keys($ref->getInterfaces());
}

4 Comments

The docs suggest that the constructor should be given a string; from the example given it appears that sometimes an object might be given.
The docs seem to be wrong, just tried and it works fine with an instance.
Yes it works with instances and strings, at least on my php version
Yeah, I was mislead by the docs (au2.php.net/manual/en/reflectionclass.construct.php). I've added a note to the page to indicate this. Learn something new every day.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.