Skip to content

Accessing ::class or calling get_class() on nullable types does not lead to a warning #13069

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
driehle opened this issue May 23, 2025 · 5 comments · May be fixed by phpstan/phpstan-src#4011

Comments

@driehle
Copy link

driehle commented May 23, 2025

Bug report

I noticed that the following code produces four warnings:

<?php

use function PHPStan\Testing\assertType;

interface ResourceInterface {}

class Person implements ResourceInterface 
{
	public function getName(): string { return 'Name'; }
}

class Account implements ResourceInterface
{
	public function getMail(): string  { return 'Mail'; }
}

function foo(?ResourceInterface $object = null): void
{
	switch ($object::class) {
		case Person::class:
			assertType(Person::class, $object);
			echo $object->getName();
			break;
		case Account::class:
			assertType(Account::class, $object);
			echo $object->getMail();
			break;
	}
}
Line Error Type
21 Expected type Person, actual: ResourceInterface|null Non-ignorable
22 Call to an undefined method ResourceInterface::getName(). method.notFound
25 Expected type Account, actual: ResourceInterface|null Non-ignorable
26 Call to an undefined method ResourceInterface::getMail(). method.notFound

Code snippet that reproduces the problem

https://phpstan.org/r/f9c2c069-07b2-46a3-b83c-837205e6581f

Expected output

The errors surprised me, as the type is actually checked and, hence, the code reported by PhpStan will not produce any errors during runtime. The feature of checking types by switch was covered in #745, #4896.

I found, however, that the code above seems to be related to $object being nullable. If you change the method signature from ?ResourceInterface $object = null to ResourceInterface $object, the errors are suddenly gone!

Next, I discovered that accessing ::class on null actually throws an error in PHP 8.4.7 (and probably all PHP 8 versions):

$ php -r "\$foo = null; var_dump(\$foo::class);"
PHP Fatal error:  Uncaught TypeError: Cannot use "::class" on null in Command line code:1
Stack trace:
#0 {main}
  thrown in Command line code on line 1

So PhpStan is actually right in reporting something, though I think the reported errors are incorect. In my opinion, PhpStan should complain about accessing ::class on nullable types.

Did PHPStan help you today? Did it make you happy in any way?

No response

@staabm
Copy link
Contributor

staabm commented May 23, 2025

You can use get_class until we are able to narrow the types better in your example

https://phpstan.org/r/6d9edb50-77bf-4997-b737-ac4a2251026d

Your analysis looks correct to me for the cases given

@driehle
Copy link
Author

driehle commented May 23, 2025

Indeed, using get_class() doesn't throw errors in PhpStan as ::class does. However, both throw a TypeError in PHP when called on a null value:

$ php -r "\$foo = null; var_dump(get_class(\$foo));"
PHP Fatal error:  Uncaught TypeError: get_class(): Argument #1 ($object) must be of type object, null given in Command line code:1
Stack trace:
#0 {main}
  thrown in Command line code on line 1

While I said the issues is PhpStan not complaining on accessing ::class on a null value, this is not fully correct. PhpStan only complains so, if the type is null and nothing else I think. See this example, where it complains about the premier two, but not about the latter two:

https://phpstan.org/r/6c8b65e4-619a-47a6-8db2-6f1dd101e75e

@driehle driehle changed the title Accessing ::class on null objects does not lead to an immediate warning Accessing ::class or calling get_class() on nullable types does not lead to a warning May 23, 2025
@VincentLanglet
Copy link
Contributor

@driehle You're doing your tests on level 6.

Union types (except null) are reported level 7
Union types with null are reporter level 8

This is a level 8 error https://phpstan.org/r/349f2d3d-a0d6-4f93-9837-1a0e20da486d

@driehle
Copy link
Author

driehle commented May 24, 2025

Ok, I think I got that. So it is then just a difference in how switch($object::class) and switch(get_class($ object)) are interpreted? But, then, why does an if (null === $object) return; before the switch solve the error?

@VincentLanglet
Copy link
Contributor

I tried a fix phpstan/phpstan-src#4011

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants