Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: autoloader #8005

Merged
merged 16 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions admin/starter/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"phpunit/phpunit": "^9.1"
},
"autoload": {
"psr-4": {
"App\\": "app/"
},
"exclude-from-classmap": [
"**/Database/Migrations/**"
]
Expand Down
15 changes: 5 additions & 10 deletions app/Config/Autoload.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,18 @@ class Autoload extends AutoloadConfig
* their location on the file system. These are used by the autoloader
* to locate files the first time they have been instantiated.
*
* The '/app' and '/system' directories are already mapped for you.
* you may change the name of the 'App' namespace if you wish,
* The 'Config' (APPPATH . 'Config') and 'CodeIgniter' (SYSTEMPATH) are
* already mapped for you.
*
* You may change the name of the 'App' namespace if you wish,
* but this should be done prior to creating any namespaced classes,
* else you will need to modify all of those classes for this to work.
*
* Prototype:
* $psr4 = [
* 'CodeIgniter' => SYSTEMPATH,
* 'App' => APPPATH
* ];
*
* @var array<string, array<int, string>|string>
* @phpstan-var array<string, string|list<string>>
*/
public $psr4 = [
APP_NAMESPACE => APPPATH, // For custom app namespace
'Config' => APPPATH . 'Config',
APP_NAMESPACE => APPPATH,
];

/**
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@
},
"autoload": {
"psr-4": {
"CodeIgniter\\": "system/"
"CodeIgniter\\": "system/",
"Config\\": "app/Config/"
},
"exclude-from-classmap": [
"**/Database/Migrations/**"
Expand Down
27 changes: 11 additions & 16 deletions system/Autoloader/Autoloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,6 @@ private function loadComposerInfo(Modules $modules): void
*/
$composer = include COMPOSER_PATH;

$this->loadComposerClassmap($composer);

// Should we load through Composer's namespaces, also?
if ($modules->discoverInComposer) {
// @phpstan-ignore-next-line
Expand All @@ -155,11 +153,11 @@ private function loadComposerInfo(Modules $modules): void
*/
public function register()
{
// Prepend the PSR4 autoloader for maximum performance.
spl_autoload_register([$this, 'loadClass'], true, true);
// Register classmap loader for the files in our class map.
spl_autoload_register([$this, 'loadClassmap'], true);

// Now prepend another loader for the files in our class map.
spl_autoload_register([$this, 'loadClassmap'], true, true);
// Register the PSR-4 autoloader.
spl_autoload_register([$this, 'loadClass'], true);

// Load our non-class files
foreach ($this->files as $file) {
Expand Down Expand Up @@ -362,9 +360,13 @@ private function loadComposerNamespaces(ClassLoader $composer, array $composerPa
{
$namespacePaths = $composer->getPrefixesPsr4();

// Get rid of CodeIgniter so we don't have duplicates
if (isset($namespacePaths['CodeIgniter\\'])) {
unset($namespacePaths['CodeIgniter\\']);
// Get rid of duplicated namespaces.
$duplicatedNamespaces = ['CodeIgniter', APP_NAMESPACE, 'Config'];

foreach ($duplicatedNamespaces as $ns) {
if (isset($namespacePaths[$ns . '\\'])) {
unset($namespacePaths[$ns . '\\']);
}
}

if (! method_exists(InstalledVersions::class, 'getAllRawData')) {
Expand Down Expand Up @@ -428,13 +430,6 @@ private function loadComposerNamespaces(ClassLoader $composer, array $composerPa
$this->addNamespace($newPaths);
}

private function loadComposerClassmap(ClassLoader $composer): void
{
$classes = $composer->getClassMap();

$this->classmap = array_merge($this->classmap, $classes);
}

/**
* Locates autoload information from Composer, if available.
*
Expand Down
2 changes: 1 addition & 1 deletion system/Config/AutoloadConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class AutoloadConfig
*/
protected $corePsr4 = [
'CodeIgniter' => SYSTEMPATH,
'App' => APPPATH, // To ensure filters, etc still found,
'Config' => APPPATH . 'Config',
];

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/system/Commands/Utilities/NamespacesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ public function testNamespacesCommandCodeIgniterOnly(): void
| Namespace | Path | Found? |
+---------------+-------------------------+--------+
| CodeIgniter | ROOTPATH/system | Yes |
| App | ROOTPATH/app | Yes |
| Config | APPPATH/Config | Yes |
| App | ROOTPATH/app | Yes |
| Tests\Support | ROOTPATH/tests/_support | Yes |
+---------------+-------------------------+--------+
EOL;
Expand Down
7 changes: 0 additions & 7 deletions tests/system/Config/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,6 @@ public function testCreateSharedInstance(): void
$this->assertSame($Config2, $Config);
}

public function testCreateNonConfig(): void
{
$Config = Config::get('Constants', false);

$this->assertNull($Config);
}

/**
* @runInSeparateProcess
* @preserveGlobalState disabled
Expand Down
4 changes: 4 additions & 0 deletions user_guide_src/source/changelogs/v4.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ Helpers and Functions
Others
======

- **Autoloader:** Autoloading performance when using Composer has been improved.
Adding the ``App`` namespace in the ``autoload.psr4`` setting in **composer.json**
may also improve the performance of your app. See :ref:`autoloader-application-namespace`.

Message Changes
***************

Expand Down
56 changes: 50 additions & 6 deletions user_guide_src/source/concepts/autoloader.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ classes that your project is using. Keeping track of where every single file is,
hard-coding that location into your files in a series of ``requires()`` is a massive
headache and very error-prone. That's where autoloaders come in.

***********************
CodeIgniter4 Autoloader
***********************

Expand All @@ -36,12 +37,14 @@ beginning of the framework's execution.
file name case is incorrect, the autoloader cannot find the file on the
server.

*************
Configuration
*************

Initial configuration is done in **app/Config/Autoload.php**. This file contains two primary
arrays: one for the classmap, and one for PSR-4 compatible namespaces.

**********
Namespaces
**********

Expand All @@ -61,21 +64,53 @@ The value is the location to the directory the classes can be found in.

php spark namespaces

.. _autoloader-application-namespace:

Application Namespace
=====================

By default, the application directory is namespace to the ``App`` namespace. You must namespace the controllers,
libraries, or models in the application directory, and they will be found under the ``App`` namespace.

Config Namespace
----------------

Config files are namespaced in the ``Config`` namespace, not in ``App\Config`` as you might
expect. This allows the core system files to always be able to locate them, even when the application
namespace has changed.

Changing App Namespace
----------------------

You may change this namespace by editing the **app/Config/Constants.php** file and setting the
new namespace value under the ``APP_NAMESPACE`` setting:

.. literalinclude:: autoloader/002.php
:lines: 2-

You will need to modify any existing files that are referencing the current namespace.
And if you use Composer autoloader, you also need to change the ``App`` namespace
in your **composer.json**, and run ``composer dump-autoload``.

.. important:: Config files are namespaced in the ``Config`` namespace, not in ``App\Config`` as you might
expect. This allows the core system files to always be able to locate them, even when the application
namespace has changed.
.. code-block:: text

{
...
"autoload": {
"psr-4": {
"App\\": "app/" <-- Change
},
...
},
...
}

.. note:: Since v4.5.0 appstarter, the ``App\\`` namespace has been added to
**composer.json**'s ``autoload.psr-4``. If your **composer.json** does not
have it, adding it may improve your app's autoloading performance.

You will need to modify any existing files that are referencing the current namespace.

********
Classmap
********

Expand All @@ -87,12 +122,21 @@ third-party libraries that are not namespaced:

The key of each row is the name of the class that you want to locate. The value is the path to locate it at.

****************
Composer Support
****************

Composer support is automatically initialized by default. By default, it looks for Composer's autoload file at
Composer support is automatically initialized by default.

By default, it looks for Composer's autoload file at
``ROOTPATH . 'vendor/autoload.php'``. If you need to change the location of that file for any reason, you can modify
the value defined in **app/Config/Constants.php**.

.. note:: If the same namespace is defined in both CodeIgniter and Composer, CodeIgniter's autoloader will be
Priority of Autoloaders
=======================

If the same namespace is defined in both CodeIgniter and Composer, Composer's
autoloader will be the first one to get a chance to locate the file.

.. note:: Prior to v4.5.0, if the same namespace was defined in both CodeIgniter and Composer, CodeIgniter's autoloader was
the first one to get a chance to locate the file.
3 changes: 1 addition & 2 deletions user_guide_src/source/concepts/autoloader/001.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ class Autoload extends AutoloadConfig
{
// ...
public $psr4 = [
APP_NAMESPACE => APPPATH, // For custom app namespace
'Config' => APPPATH . 'Config',
APP_NAMESPACE => APPPATH,
];

// ...
Expand Down
1 change: 1 addition & 0 deletions user_guide_src/source/dbmgmt/migration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ For example, assume that we have the following namespaces defined in our Autoloa
configuration file:

.. literalinclude:: migration/004.php
:lines: 2-

This will look for any migrations located at both **APPPATH/Database/Migrations** and
**ROOTPATH/MyCompany/Database/Migrations**. This makes it simple to include migrations in your
Expand Down
4 changes: 2 additions & 2 deletions user_guide_src/source/dbmgmt/migration/004.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

$psr4 = [
'App' => APPPATH,
'MyCompany' => ROOTPATH . 'MyCompany',
APP_NAMESPACE => APPPATH,
'MyCompany' => ROOTPATH . 'MyCompany',
];
4 changes: 2 additions & 2 deletions user_guide_src/source/general/modules/001.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

class Autoload extends AutoloadConfig
{
// ...
public $psr4 = [
APP_NAMESPACE => APPPATH, // For custom namespace
'Config' => APPPATH . 'Config',
APP_NAMESPACE => APPPATH,
'Acme\Blog' => ROOTPATH . 'acme/Blog',
];

Expand Down
Loading