I've seen this before and now again in http://qa.drupal.org/pifr/test/471168. So I looked into it.
When you enable xdebug, you get the stack trace, which shows something like this:
PHP Fatal error: Class 'Insert' not found in /core/modules/system/lib/Drupal/system/Tests/Menu/TreeAccessTest.php on line 108
PHP Stack trace:
PHP 1. {main}() /core/scripts/run-tests.sh:0
PHP 2. simpletest_script_get_all_tests() /core/scripts/run-tests.sh:54
PHP 3. simpletest_test_get_all() /core/scripts/run-tests.sh:336
PHP 4. class_exists() /core/modules/simpletest/simpletest.module:484
PHP 5. Symfony\Component\ClassLoader\UniversalClassLoader->loadClass() /core/modules/simpletest/simpletest.module:0
PHP 6. _drupal_error_handler() /core/modules/simpletest/simpletest.module:251
PHP 7. _drupal_error_handler_real() /core/includes/bootstrap.inc:2248
PHP 8. _drupal_log_error() /core/includes/errors.inc:77
PHP 9. watchdog() /core/includes/errors.inc:212
PHP 10. dblog_watchdog() /core/includes/bootstrap.inc:1797
PHP 11. Drupal\Core\Database\Connection->insert() /core/modules/dblog/dblog.module:148
So what happens is this. We are entering the classloader, during loading the class we notice something that's not right, in my case a dumb strict error. PHP error handling is triggered, dblog_watchdog() is invoked and that tries to create an INSERT query to log the error to the database. That goes all the way down to Connection::getDriverClass() which checks if ""Drupal\\Core\\Database\\Driver\\{$driver}\\{$class}" exists. Because we are already in the process of loading a class, PHP doesn't attempt to invoke the classloader again, assuming that this could result in an endless loop or something.
Then the bogus fallback comes into play that falls back to just "Insert" (The fallback logic should be Drupal\Core\Database\Query\$class, which would also mean that we wouldn't need those "dumb" empty Driver classes). That is returned to the caller which tries to instantiate that class and... kaboom.
Because we are however still in the error handler within the classloader, the fatal error is shown on the line where the error was triggered.. the closing } of whatever class caused this.
Isn't this an interesting pile of .... fun?!
I do not have the slightest clue on how to fix this. The fallback logic should be fixed but that will end up with the exact same result. Any ideas?
Comments
Comment #1
chx commentedThis looks like a chx issue. I will think of something.
Comment #2
berdirI guess what we could do is if the fallback class also isn't found, do a hardcoded require_once of __DIR__ /Query/Insert.php because we *know* it has to be there and assume that the classloader is for whatever reason failing on us.
But we would be using the fallback class which might not work?
Comment #3
chx commentedComment #4
dawehnerIsn't this more of a database system issue?
Comment #15
mfbI suspect this issue could be closed as outdated, unless someone can provide steps to reproduce?
This issue was created a couple years before PHP 7.0 was released, at which point E_STRICT is not used anymore afaik. There are still compile warnings, but I believe these aren't sent to custom error handlers, as per https://www.php.net/manual/en/function.set-error-handler.php
For errors/notices that are being sent to the error handler, the only issue with autoloading I've seen recently is an opcache bug in PHP 8.1 - see https://github.com/php/php-src/pull/8297
There certainly was an issue here in the past - see reports such as https://bugs.php.net/bug.php?id=60149 for the original issue where autoload couldn't be triggered from compiler.
Comment #16
berdirFine by me. I don't think it was specifically about E_STRICT, but quite possible that it doesn't happen anymore in that way. The modern version of this is unserialize errors in phpunit tests, which is kinda the same problem, this looks like an example of that: #3276842: Asserting arrays are equal fails for the wrong reason
Comment #17
mfbI think E_STRICT was relevant because many of those errors were sent to the custom error handler, and autoload wasn't possible, but nowadays E_STRICT isn't used and any compile-time warnings/deprecations/etc. just aren't sent to the custom error handler - as far as I've seen - so they get logged by PHP rather than Drupal. This is kind-of unfortunate as they get "swallowed" unless someone is looking at wherever PHP is logging.
Comment #18
mfbOut of curiosity, I dug into this a bit more and found that it's Opcache that prevents some compile-time warnings and deprecations from being sent to Drupal's custom error handler; these are sent to the error handler if you disable Opcache. See also https://bugs.php.net/bug.php?id=79184
But in any case, I haven't reproduced the original issue so I think this can be closed.