From be3482f3396631a8e55f4bb161344395ac716d53 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 8 Aug 2024 12:57:34 +0800 Subject: [PATCH 1/2] MDL-82747 core: Provide a standard way to register the Autoloader --- .upgradenotes/MDL-82747-2024080805044739.yml | 10 ++++++++++ admin/cli/install.php | 9 ++------- install.php | 8 ++------ lib/classes/component.php | 11 +++++++++++ lib/setup.php | 8 ++------ 5 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 .upgradenotes/MDL-82747-2024080805044739.yml diff --git a/.upgradenotes/MDL-82747-2024080805044739.yml b/.upgradenotes/MDL-82747-2024080805044739.yml new file mode 100644 index 00000000000..9ef00af1a94 --- /dev/null +++ b/.upgradenotes/MDL-82747-2024080805044739.yml @@ -0,0 +1,10 @@ +issueNumber: MDL-82747 +notes: + core: + - message: >- + The Moodle autoloader should now be registered using + `\core\component::register_autoloader` rather than manually doing so in + any exceptional location which requires it. It is not normally necessary + to include the autoloader manually, as it is registered automatically + when the Moodle environment is bootstrapped. + type: improved diff --git a/admin/cli/install.php b/admin/cli/install.php index 56849ee9523..440a3d7ef87 100644 --- a/admin/cli/install.php +++ b/admin/cli/install.php @@ -179,13 +179,8 @@ ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include // The core_component class can be used in any scripts, it does not need anything else. require_once($CFG->libdir.'/classes/component.php'); -// Register our classloader, in theory somebody might want to replace it to load other hacked core classes. -// Required because the database checks below lead to session interaction which is going to lead us to requiring autoloaded classes. -if (defined('COMPONENT_CLASSLOADER')) { - spl_autoload_register(COMPONENT_CLASSLOADER); -} else { - spl_autoload_register('core_component::classloader'); -} +// Register our classloader. +\core\component::register_autoloader(); require_once($CFG->libdir.'/classes/text.php'); require_once($CFG->libdir.'/classes/string_manager.php'); diff --git a/install.php b/install.php index 1b78e9e9fc2..da592f0c692 100644 --- a/install.php +++ b/install.php @@ -202,12 +202,8 @@ if (!empty($memlimit) and $memlimit != -1) { // the problem is that we need specific version of quickforms and hacked excel files :-(. ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path')); -// Register our classloader, in theory somebody might want to replace it to load other hacked core classes. -if (defined('COMPONENT_CLASSLOADER')) { - spl_autoload_register(COMPONENT_CLASSLOADER); -} else { - spl_autoload_register('core_component::classloader'); -} +// Register our classloader. +\core\component::register_autoloader(); // Continue with lib loading. require_once($CFG->libdir.'/classes/text.php'); diff --git a/lib/classes/component.php b/lib/classes/component.php index 7da97fbf726..91f998077e6 100644 --- a/lib/classes/component.php +++ b/lib/classes/component.php @@ -149,6 +149,17 @@ class component { \Slim::class => 'lib/slim/slim/Slim', ]; + /** + * Register the Moodle class autoloader. + */ + public static function register_autoloader(): void { + if (defined('COMPONENT_CLASSLOADER')) { + spl_autoload_register(COMPONENT_CLASSLOADER); + } else { + spl_autoload_register([self::class, 'classloader']); + } + } + /** * Class loader for Frankenstyle named classes in standard locations. * Frankenstyle namespaces are supported. diff --git a/lib/setup.php b/lib/setup.php index 1fb63fc3e6f..0a14e5f3981 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -594,12 +594,8 @@ if (NO_OUTPUT_BUFFERING) { // the problem is that we need specific version of quickforms and hacked excel files :-(. ini_set('include_path', $CFG->libdir . '/pear' . PATH_SEPARATOR . ini_get('include_path')); -// Register our classloader, in theory somebody might want to replace it to load other hacked core classes. -if (defined('COMPONENT_CLASSLOADER')) { - spl_autoload_register(COMPONENT_CLASSLOADER); -} else { - spl_autoload_register([\core_component::class, 'classloader']); -} +// Register our classloader. +\core\component::register_autoloader(); // Special support for highly optimised scripts that do not need libraries and DB connection. if (defined('ABORT_AFTER_CONFIG')) { From 08f8b5894530b6e3a83b2d338c5e564efeec67e2 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 8 Aug 2024 12:58:33 +0800 Subject: [PATCH 2/2] MDL-82747 core: Register composer autoload files Unfortunately PHP does not provide any means to autoload the files that a functions is located in, even if they are in an namespace. To work around this, Composer makes use of an `autoload.files` section in the `composer.json` file. Shortly after the Composer autoloader is registered with the `spl_autoload_register` call it also includes any files listed in this section. Moodle does not do this and really we should be doing so. This change adds a section to the autoloader registration method which loads all of the files defined in any third-party library included in our `lib` directory which contains any `composer.json` file with such a stanza. --- lib/classes/component.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/classes/component.php b/lib/classes/component.php index 91f998077e6..fa4e64daa77 100644 --- a/lib/classes/component.php +++ b/lib/classes/component.php @@ -149,6 +149,24 @@ class component { \Slim::class => 'lib/slim/slim/Slim', ]; + /** + * An array containing files which are normally in a package's composer/autoload.files section. + * + * PHP does not provide a mechanism for automatically including the files that methods are in. + * + * The Composer autoloader includes all files in this section of the composer.json file during the instantiation of the loader. + * + * @var array + */ + protected static $composerautoloadfiles = [ + 'lib/aws-sdk/src/functions.php', + 'lib/guzzlehttp/guzzle/src/functions_include.php', + 'lib/jmespath/src/JmesPath.php', + 'lib/php-di/php-di/src/functions.php', + 'lib/ralouphi/getallheaders/src/getallheaders.php', + 'lib/symfony/deprecation-contracts/function.php', + ]; + /** * Register the Moodle class autoloader. */ @@ -158,6 +176,15 @@ class component { } else { spl_autoload_register([self::class, 'classloader']); } + + // Load any composer-driven autoload files. + // This is intended to mimic the behaviour of the standard Composer Autoloader. + foreach (static::$composerautoloadfiles as $file) { + $path = dirname(__DIR__, 2) . '/' . $file; + if (file_exists($path)) { + require_once($path); + } + } } /**