If you’ve spent much time upgrading older websites to PHP 7, it’s likely you have encountered the annoying situation where PHP notices are printed directly into the HTML output, causing them to display in an ugly, unformatted jumble at the top of the page. The effect looks something like this:
Ouch! To make matters worse, sometimes these notices are only occasionally displayed, making it harder to track down the source of the problem (e.g. if you reload the page to reproduce before making a note of the line number, and then cannot get the message back again).
Oddly enough, other PHP notices, including some PHP language deprecations, are handled normally. They show up consistently, and are either displayed or hidden based on the preferences set for the site, as shown in the example below:
WTF PHP? Oh, Okay.
Why should a PHP notice be processed differently in different circumstances? This situation feels like something is wrong with PHP; developer experience is improved when systems behave consistently, and this behavior is definitely not consistent. However, once the actual operations being done by PHP are considered, the behavior is perfectly reasonable, and makes sense.
The answer lies with opcache, the newly built-in mechanism for increasing the performance of PHP 7 applications. Opcache pre-compiles and optimizes PHP, and caches the results to make subsequent application transactions significantly faster. When opcache is enabled, as it is by default in PHP 7, certain notices can only be displayed when the PHP code is compiled, which is before the CMS can be booted or any error handlers can be installed. When subsequent page requests are made and the PHP code is fetched from the cache, the compilation step does not run, so notices related to compilation are not generated. Thus, if you disable opcache, then you will see parse-time notices on every page load, as shown in the second example. This is explained in the Pantheon documentation page on debugging intermittent PHP 7 notices:
When opcache is in use, PHP will print any notice emitted during source code processing directly to the standard output, ignoring any error handler that may be set. These notices may still be disabled by setting error_reporting to ignore E_DEPRECATED; however, Drupal always enables E_DEPRECATED in error_reporting early in its bootstrap process, so these notices will be printed if display_errors is set to on.Opcache also influences when this error is displayed. Since opcache caches the compiled form (opcodes) of the PHP that is being executed, the deprecation notices will not be printed when the PHP opcodes are fetched from the opcache. This is what leads to the intermittent nature of this problem.
At the moment, the only PHP notice that falls into this category is the “deprecated constructor” notice shown above. However, as PHP continues to evolve, it is possible that more notices of this sort might be added to the language. There has been a trend lately in PHP to favor type-safe interfaces over untyped functions, as this practice leads to more reliable code. If the trend towards more strict standards continues in PHP 8, it is entirely possible that more deprecation notices will be added during the parsing phase. If you are seeing intermittent errors in your PHP output, keep opcache in mind, as that is likely going to be the thing that keeps you from seeing coding notices all the time.
Advice on finding parse-time notices without disabling opcache are provided on the previously-mentioned documentation page. The best remedy, though, is to stay up to date with your PHP practices, and also ensure that you are using the latest version of any libraries you obtained from other sources. If you’re using something that’s out of date, it’s likely that the notices you are seeing have already been fixed.