Req #78351 [Opn]: Possible to check for invalid class
| From: | php at braten dot be | Date: | Thu, 22 Aug 2019 13:27:49 +0000 |
| Subject: | Req #78351 [Opn]: Possible to check for invalid class | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-222364@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78351&edit=1
ID: 78351
User updated by: php at braten dot be
Reported by: php at braten dot be
Summary: Possible to check for invalid class
Status: Open
Type: Feature/Change Request
Package: Scripting Engine problem
Operating System: Irrelevant
PHP Version: Next Minor Version
Block user comment: N
Private report: N
New Comment:
More discussion about this can be found at https://github.com/symfony/symfony/issues/32995
Previous Comments:
------------------------------------------------------------------------
[2019-07-29 18:36:55] nicolas dot grekas+php at gmail dot com
In https://github.com/symfony/symfony/issues/32395#issuecomment-509593220,
Nikita gives us the following problematic example on 7.4:
<quote>
// A.php
class A {
public function foo($x): B {}
}
// B.php
class B extends A {
public function foo($x): C {}
}
// C.php
class C extends B implements DoesNotExist {
}
// main.php
new C;
What happens now is the following:
1. Autoload C. The class C is registered provisionally.
2. Autoload the parent B. The class B is registered provisionally.
3.Autoload the parent A. The class A is registered provisionally.
4. The class A is verified (trivially) and registered fully.
5. The class B is verified and registered fully (and may already be used). During the verification
it makes use of the fact that C is a subclass of B, otherwise the return types would not be
covariant.
6. Autoload the interface DoesNotExist, which throws an exception.
After these steps have happened ... what can we do now? We can't fully register the class C,
because the interface it implements does not exist. We can't remove the provisionally
registered class C either, because then a new class C that is not a subclass of B could be
registered, and thus violate the variance assumption we made above.
</quote>
Then a commenter suggests:
<quote>
Would it be possible to mark a provisionally registered class as âin useâ as soon as it is
referenced somewhere?
This way we could determine in an exception case if it is OK to remove the provisionally registered
class and gracefully recover or if we have to throw a fatal error.
In your example this would mean that once class B is verified it would mark class C as âin
useâ. When loading DoesNotExist throws the exception then, we would throw a fatal error because
class C is âin useâ.
This way we could gracefully recover for most cases while resulting in a fatal error for the
impossible cases, which sounds like a perfect trade-off to me.
</quote>
Implementing that proposal, if technically possible, would be enough to have code that provided the
describe feature before 7.4 continue to work in most real-life situations.
This is going to be a critical issue for Symfony at least, where this resiliency is pretty much
needed.
Thanks for considering.
------------------------------------------------------------------------
[2019-07-29 18:14:07] php at braten dot be
Description:
------------
It should be possible in PHP to check if a class exists or has a certain method without throwing a
fatal error if the class is invalid.
This has become an issue since https://bugs.php.net/bug.php?id=76980 was fixed,
and is described in more detail in https://github.com/symfony/symfony/issues/32395
This is a feature request for the next version of PHP to allow functions like get_class_methods,
get_class_vars, get_parent_class, is_a, is_subclass_of, class_exists, class_implements,
class_parents, trait_exists, defined, interface_exists, method_exists, property_exists, is_callable
to be called without throwing a *fatal* error if a class or interface does not exist.
It can be ok if you later do "new" on the same class, that PHP must throw a fatal error.
But it should be possible to get a negative result from the above mentioned functions without a
fatal error.
Test script:
---------------
https://github.com/derrabus/symfony-32395-reproducer
Expected result:
----------------
Possible to catch the error and resume.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78351&edit=1