80

I've got this:

    use XXX\Driver\Driver;

...

var_dump(class_exists('Driver')); // false
        $driver = new Driver(); // prints 123123123 since I put an echo in the constructor of this class
        exit;

Well... this behaviour is quite irrational (creating objects of classes that according to PHP do not exist). Is there any way to check if a class exist under given namespace?

Taruo Gene
  • 1,023
  • 1
  • 9
  • 16
  • http://www.php.net/class_exists look at the comments how namespaces are given – Royal Bg Mar 14 '14 at 14:13
  • See also "[Is there a namespace aware alternative to PHP's class_exists()?](http://stackoverflow.com/q/15839292/90527)" – outis Sep 02 '15 at 21:09

2 Answers2

130

In order to check class you must specify it with namespace, full path:

namespace Foo;
class Bar
{
}

and

var_dump(class_exists('Bar'), class_exists('\Foo\Bar')); //false, true

-i.e. you must specify full path to class. You defined it in your namespace and not in global context.

However, if you do import the class within the namespace like you do in your sample, you can reference it via imported name and without namespace, but that does not allow you to do that within dynamic constructions and in particular, in-line strings that forms class name. For example, all following will fail:

namespace Foo;
class Bar {
    public static function baz() {} 
}

use Foo\Bar;

var_dump(class_exists('Bar')); //false
var_dump(method_exists('Bar', 'baz')); //false

$ref = "Bar";
$obj = new $ref(); //fatal

and so on. The issue lies within the mechanics of working for imported aliases. So when working with such constructions, you have to specify full path:

var_dump(class_exists('\Foo\Bar')); //true
var_dump(method_exists('\Foo\Bar', 'baz')); //true

$ref = 'Foo\Bar';
$obj = new $ref(); //ok
Andy
  • 4,901
  • 5
  • 35
  • 57
Alma Do
  • 37,009
  • 9
  • 76
  • 105
  • 2
    Note that `Driver` is imported in the question, so the last example in this answer doesn't describe the case in question. `use \Foo\Bar; $obj = new Bar;` is perfectly legal. The real issue is that `class_exists()` doesn't take aliases into account. – outis Sep 02 '15 at 20:51
  • @outis, Thank you.I was in an infinite loop for a while after reading this answer until I got to your comment. – sanchez Dec 15 '15 at 01:09
  • @Alma Do - Why not considering an important comment for few months? downvote from me until woken up and corrected. – sanchez Dec 15 '15 at 01:11
  • 1
    @san.chez while the thing being said is true, the real issue isn't about `class_exists`, it's about PHP and substitution mechanics for aliased entities. Added explanation that refer to generic case. – Alma Do Dec 21 '15 at 08:57
  • Your last example needs double quoted backslashes – scrowler Jan 18 '17 at 04:05
  • 2
    class_exists('\\Foo\\Bar') doesn't need the double slashes since it uses single quote syntax for the string. http://php.net/manual/en/language.namespaces.dynamic.php – DrLightman Mar 12 '17 at 10:02
  • -1 THis is not a scalable solution. Because if you change your class' namespace, then you will have to hunt down all the places where you have used the class_exists() with the hardcoded namespace and change all of them. Use `if (class_exists(Bar::class))` instead. – asiby Apr 24 '20 at 20:28
  • 1
    @AlmaDo, honestly I am not sure where you get your information. But at the end of day, you can do whatever solution that works for you. PHP 5.5 was released on 2013-06-20 (look ip up at https://www.php.net/releases/index.php#5.5.0) and this question was asked on 2014-03-14. How can any answer to this question precede the question itself and let alone the PHP 5.5 release date? Using `::class` will never bring up multiple result. How is that possible? The point is ... your answer which did not work for my use cases. I had to use @outis solution which I am using in production now. – asiby Jun 01 '20 at 04:48
  • (EDIT: I checked the date for the wrong PHP release, page is the same); I'm not sure how it "did not work" without much details. The answer will work because there's an explicit unique NS reference. And I still don't see how `::class` can help because - while - yes, it is a unique reference, it must be called on a class literal, not a string and OP wanted to check it on an arbitrary string. P.S. "Hunting down" class after NS change means that such a check that OP needs was used for wrong purpose. One of the few reasons to do the check is class loading which should occur in one place. – Alma Do Jun 13 '20 at 20:08
34

The issue (as mentioned in the class_exists() manual page user notes) is that aliases aren't taken into account whenever a class name is given as a string. This also affects other functions that take a class name, such as is_a(). Consequently, if you give the class name in a string, you must include the full namespace (e.g. '\XXX\Driver\Driver', 'XXX\\Driver\\Driver').

PHP 5.5 introduced the class constant for just this purpose:

use XXX\Driver\Driver;
...
if (class_exists(Driver::class)) {
    ...
}
outis
  • 75,655
  • 22
  • 151
  • 221