Bug #80009 [Nab]: Fatal Error is not caught with Throwable

From: Date: Mon, 24 Aug 2020 14:47:14 +0000
Subject: Bug #80009 [Nab]: Fatal Error is not caught with Throwable
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-228738@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=80009&edit=1 ID: 80009 User updated by: brucekwells at gmail dot com Reported by: brucekwells at gmail dot com Summary: Fatal Error is not caught with Throwable Status: Not a bug Type: Bug Package: Compile Failure Operating System: Windows 10.0 build 19041 AMD64 PHP Version: 7.4.9 Assigned To: cmb Block user comment: N Private report: N New Comment: Thanks for the explanation. I was hoping it was going to be some sort of "opps, missed that case, easy fix." I'll look into your suggestion of a separate failable process. And thanks for all the hard work on PHP, it just keeps getting better and better. Looking forward to 8 and beyond. Previous Comments: ------------------------------------------------------------------------ [2020-08-24 07:42:28] nikic@php.net > Now it is possible this error is intended to not be catchable. Is there a list of PHP errors > that are documented as not being catchable? As a very rough rule: Any error thrown during compilation rather than run-time cannot be caught. We'd love to make everything throw, but it would take too much work for some of them. If you're just validating files, the easiest way to do so would probably be to fork/exec a new process that can freely fatal. ------------------------------------------------------------------------ [2020-08-23 17:08:21] cmb@php.net The nomenclature isn't optimal, or at least there is the subtle difference between Error (an exception), and "real" errors (E_ERROR etc.). See set_exception_handler() vs. set_error_handler(). Anyhow, that doesn't really matter, since either kind of error isn't really meant to be caught (even if it's possible for Error exceptions). Instead they signal programming errors which should be resolved. Finally, it is simply not possible to continue execution for all kinds of error conditions, because the engine is in an invalid state. This is why there are still errors which are not Exceptions. ------------------------------------------------------------------------ [2020-08-23 15:34:46] brucekwells at gmail dot com So I am confused. Here is the manual entry for PHP 7 errors which states they are handled by throwing exceptions of type Error, which extends Throwable. https://www.php.net/manual/en/language.errors.php7.php So I can catch the following fatal errors by catching Throwable: - Return value of TestExtended::returnString() must be of the type int, string returned - Class 'TestExtendedd' not found - Call to undefined method TestExtended::returnStringx() But apparently I can not catch - Declaration of TestExtended::returnString(): int must be compatible with TestBase::returnString(): string Now the manual does say "most errors" are handled by exceptions. Apparently this one is not. I would consider this a bug. My use case (that I found in the wild) is some Google code that does exactly what I have in the test case. I noticed this when I tried to run the ReflectorClass on it. The error was thrown but not caught. I want to write unit tests that will load every class using the ReflectionClass. The reason to do this is I can not new every possible class due to required parameters in the constructor. But the ReflectionClass does not construct the object, it merely loads the class, and in so doing, causes PHP to generate this error. I also have used the nikic/PhpParser to analyze the syntax of each PHP file, but it can not detect this problem, as it does not know the parent class declared the return value differently, as it is just parsing the file based on syntax rules, and it is syntactically correctly. So my unit tests can now do a syntax check on every single file in my source tree with PhpParser, and if this worked as documented, I would use ReflectionClass to load every class (including all it's parents, which may not be my code) and check for errors. I would not be executing any code, but simply doing a complete syntax and essentially a lint / linker type check as well. Too often people use unit test code coverage to try to find all these types of errors, but that is a very manual and error prone process. My solution would make PHP much more like a compiled language where all code must pass a basic syntax check, meaning it was loaded and parsed by PHP itself. This would be a HUGE improvement for insuring PHP code in your project is syntactically correct. Now it is possible this error is intended to not be catchable. Is there a list of PHP errors that are documented as not being catchable? And thanks for the prompt reply over the weekend! I think if we could get PHP to throw exceptions on errors in all cases, we would have a much better language in the long run. Thanks for your consideration. ------------------------------------------------------------------------ [2020-08-22 20:49:36] cmb@php.net Thank you for taking the time to write to us, but this is not a bug. Please double-check the documentation available at http://www.php.net/manual/ and the instructions on how to report a bug at http://bugs.php.net/how-to-report.php There is a difference between E_(*_)ERROR and Throwable. Just try without the try-catch-statement. ------------------------------------------------------------------------ [2020-08-22 18:04:44] brucekwells at gmail dot com Description: ------------ Some Fatal Errors are caught in this script and some are not. Comment out the "extends TestBase" of the TestExtended class, and this example will catch the error: Return value of TestExtended::returnString() must be of the type int, string returned Or change the class in the new statement to an undefined class. Or change the method call. Both are fatal errors, both caught. But as written, this script does not catch the fatal error. Test script: --------------- <?php try { class TestBase { public function returnString() : string { return __METHOD__; } } class TestExtended extends TestBase { public function returnString() : int { return __METHOD__; } } $test = new TestExtended(); echo $test->returnString(); } catch (\Throwable $e) { echo 'Caught error: ' . $e->getMessage(); } phpinfo(); Expected result: ---------------- 'Caught error: ' followed by PHP error message is printed, followed by phpinfo() output. Actual result: -------------- Fatal error message is printed the standard PHP error handler and is not prefixed by 'Caught error: '. phpinfo() is also not printed. ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=80009&edit=1

« previous php.bugs (#228738) next »