Christopher Francisco
Christopher Francisco

Reputation: 16278

Does PHP 7 have a way to crash on non-existing class when using the `MyClass::class` notation?

A basic use case would be calling MyEventListener::class without having imported use MyNamespace\MyEventListener. The result would be a broken piece of code that's relatively hard to debug.

Does PHP 7 provide a directive to crash instead of returning the class name if no class exists? For example:

After calling use Foo\Bar;, Bar::class would return 'Foo\Bar'.

But if no import statement, PHP returns 'Bar', even though the class doesn't exist, not even in the global namespace.

Can I make it crash somehow?

Upvotes: 2

Views: 998

Answers (3)

Eugene Kaurov
Eugene Kaurov

Reputation: 2991

PhpStorm proposes and generates hints like ArrayShape, Pure, etc.

But automatically it is adding

php use JetBrains\PhpStorm\ArrayShape;

or another.

Is not that dangerous that on some production server I will get error 'Class JetBrains\PhpStorm\ArrayShape not found'?

(c)LazyOne:

  1. Well, just use composer require --dev jetbrains/phpstorm-attributes to add such classes to your project. See github.com/JetBrains/phpstorm-attributes

  2. As long as instance of such a class is not actually gets instantiated (created) you should have no error because use statement is just a declaration.

Upvotes: 0

Derrek Bertrand
Derrek Bertrand

Reputation: 626

The thing you need to keep in mind is that use Foo\Bar; is not "importing" anything. It is telling the compiler: when I say "Bar" I mean Bar from the namespace Foo.

Bar::class is substituted blindly with the string "Foo\Bar". It isn't checking anything.

Until you attempt to instantiate or interact with a class it will not check to see if it exists. That said, it does not throw an Exception, it throws an Error:

// this doesn't exist!
use Foo/Bar;

try {
    $instanceOfBar = new Bar();
}
catch (Error $e) {
    // catching an Exception will not work
    // Throwable or Error will work
}

You can trap and check for non-existent classes at run time, but until you do it will happily toss around strings referring to classes that don't exist.

This is a blessing in the case of Laravel's IoC container and autoloader that abuses this to alias classes as convenient top-level objects. A curse, if you were expecting PHP to throw a fuss on ::class not existing.


Update: My suggestion for anyone worried about this problem is to use PHPStan in your testing pipeline. It prevents a lot of mistakes, and unlike php -l it will catch if you were to try and interact with a non-existent class.

Upvotes: 4

TinkerTenorSoftwareGuy
TinkerTenorSoftwareGuy

Reputation: 797

As far as I know you're going to get a nice error message when you try to instantiate a class that cannot be found through autoloading or explicitly added.

If you want to check if the class exists, first, try this:

$classOutsideNamespaceExists = class_exists('Bar');
$classInsideNameSpaceExists = class_exists('\\Foo\\Bar'));

Or you could try this syntax available since PHP 5.5:

class_exists(MyClass::class)

Finally, you can always use the tried and true method of a try-catch block.

try {
 $instanceOfMyClass = new MyClass();
}
catch (Exception $e) {
  // conclude the class does not exist and handle accordingly
}

Upvotes: 1

Related Questions