diff --git a/src/moduleutils/PhutilBootloader.php b/src/moduleutils/PhutilBootloader.php --- a/src/moduleutils/PhutilBootloader.php +++ b/src/moduleutils/PhutilBootloader.php @@ -204,29 +204,40 @@ $root = $_SERVER['PHUTIL_LIBRARY_ROOT']; } } - $okay = $this->executeInclude($root.$path.'/__phutil_library_init__.php'); - if (!$okay) { - throw new PhutilBootloaderException( - "Include of '{$path}/__phutil_library_init__.php' failed!"); - } + + $this->executeInclude($root.$path.'/__phutil_library_init__.php'); } public function loadLibrarySource($library, $source) { $path = $this->getLibraryRoot($library).'/'.$source; - $okay = $this->executeInclude($path); - if (!$okay) { - throw new PhutilBootloaderException("Include of '{$path}' failed!"); - } + $this->executeInclude($path); } private function executeInclude($path) { - // Suppress warning spew if the file does not exist; we'll throw an - // exception instead. We still emit error text in the case of syntax errors. - $old = error_reporting(E_ALL & ~E_WARNING); + // Include the source using `include_once`, but convert any warnings or + // errors into exceptions. + + // Some messages, including "Declaration of X should be compatible with Y", + // changed from E_STRICT to E_WARNING in PHP7, and do not cause + // `include_once` to return an error code. Use error_get_last() to make + // sure we're catching everything in every PHP version. + + error_clear_last(); + + $old = error_reporting(0); $okay = include_once $path; error_reporting($old); - return $okay; + if (!$okay) { + throw new Exception("Source file \"{$path}\" failed to load."); + } + + $last = error_get_last(); + if ($last !== null) { + $message = $last['message']; + throw new Exception( + "Error while loading file \"{$path}\": {$message}"); + } } private function loadExtension($library, $root, $path) { @@ -235,11 +246,7 @@ $old_classes = array_fill_keys(get_declared_classes(), true); $old_interfaces = array_fill_keys(get_declared_interfaces(), true); - $ok = $this->executeInclude($path); - if (!$ok) { - throw new PhutilBootloaderException( - "Include of extension file '{$path}' failed!"); - } + $this->executeInclude($path); $new_functions = get_defined_functions(); $new_functions = array_fill_keys($new_functions['user'], true);