One of the interesting changes betweem Magento 2’s merchant beta and their official release was/is the registration.php
file. Every module now needs this file at its root folder for Magento to identify it as a module.
You can see the list of folders Magento scans for modules (i.e. registration.php
) here
#File: app/etc/NonComposerComponentRegistration.php
$pathList[] = dirname(__DIR__) . '/code/*/*/cli_commands.php';
$pathList[] = dirname(__DIR__) . '/code/*/*/registration.php';
$pathList[] = dirname(__DIR__) . '/design/*/*/*/registration.php';
$pathList[] = dirname(__DIR__) . '/i18n/*/*/registration.php';
$pathList[] = dirname(dirname(__DIR__)) . '/lib/internal/*/*/registration.php';
$pathList[] = dirname(dirname(__DIR__)) . '/lib/internal/*/*/*/registration.php';
foreach ($pathList as $path) {
// Sorting is disabled intentionally for performance improvement
$files = glob($path, GLOB_NOSORT);
if ($files === false) {
throw new RuntimeException('glob() returned error while searching in '' . $path . ''');
}
foreach ($files as $file) {
include $file;
}
}
You may think this is an inefficient scanning of of directories for a modules (vs. Magento 1’s verbose module declaration files in app/etc/modules/*
). You wouldn’t be wrong, but Magento works around this by hijacking Composer’s autoloader include
functionality. If you take a look at any core module’s composer.json
file, you’ll see something like the following
#File: vendor/magento/module-payment/composer.json
//...
"files": [
"registration.php"
],
//...
This bit of composer configuration ensures each module’s registration.php
is loaded automatically, without a full directory scan for each Magento module. If you’re curious about the specifics, I wrote in detail about composer’s autoloading features in my Laravel, Composer, and the State of Autoloading series.