Unset Composer's autoloader from the autoload stack#5834
Conversation
| $paths = $composer->getPrefixesPsr4(); | ||
| $classes = $composer->getClassMap(); | ||
|
|
||
| $composer->unregister(); |
There was a problem hiding this comment.
This is in the discoverComposerNamespaces() method.
So when $modules->discoverInComposer is false, it does not run.
When $modules->discoverInComposer is false, Composer autoloader is still enabled.
Is it intentional?
There was a problem hiding this comment.
Composer's autoloader is only enabled when included in $this->discoverComposerNamespaces(). In the code, once we include COMPOSER_PATH, Composer will register its autoloader and prepend it in the autoload stack. If $modules->discoverInComposer is false, then COMPOSER_PATH is not included and won't be registered.
There was a problem hiding this comment.
<?php
namespace App\Controllers;
use Closure;
class Home extends BaseController
{
public function index()
{
foreach (spl_autoload_functions() as $autoloader) {
switch ($autoloader) {
case $autoloader instanceof Closure:
echo get_class($autoloader) . PHP_EOL;
break;
case is_string($autoloader[0]):
echo $autoloader[0] . '::' . $autoloader[1] . PHP_EOL;
break;
case is_object($autoloader[0]):
echo get_class($autoloader[0]) . '::' . $autoloader[1] . PHP_EOL;
break;
}
}
}
}With this PR, there is no Composer autoloader.
$ php public/index.php
CodeIgniter\Autoloader\Autoloader::loadClassmap
CodeIgniter\Autoloader\Autoloader::loadClass
PHPStan\PharAutoloader::loadClass
Closure
Next, make $discoverInComposer false.
--- a/app/Config/Modules.php
+++ b/app/Config/Modules.php
@@ -29,7 +29,7 @@ class Modules extends BaseModules
*
* @var bool
*/
- public $discoverInComposer = true;
+ public $discoverInComposer = false;
/**
* --------------------------------------------------------------------------$ php public/index.php
Composer\Autoload\ClassLoader::loadClass
CodeIgniter\Autoloader\Autoloader::loadClassmap
CodeIgniter\Autoloader\Autoloader::loadClass
PHPStan\PharAutoloader::loadClass
Closure
Composer autoloader is registered.
There was a problem hiding this comment.
Okay. So there's a place in the application lifecycle where Composer is included regardless of the $discoverInComposer flag. I'll take a look into it but most probably it shouldn't be included automatically.
There was a problem hiding this comment.
Found it!
In system/bootstrap.php and system/Test/bootstrap.php, we require_once COMPOSER_PATH regardless of the $discoverInComposer flag, which shouldn't be the case as it is handled already in the Services::autoloader()->initialize() call.
There was a problem hiding this comment.
if (is_file(COMPOSER_PATH)) {
require_once COMPOSER_PATH;
}
When a user does not have Composer classmap (don't use So this PR is okay unless there is no bugs in the CI4 autoloader of PSR-4 class loading? |
|
@paulbalandan This is not directly related this PR, but I think the following logic is the cause of the error,
CodeIgniter4/system/CLI/Commands.php Lines 90 to 103 in 7107e78 |
|
Looks like good work and review underway already, let me know if you need me. |
|
136903c to
85f7e69
Compare
|
@paulbalandan If you disable Auto-Discovery is the functionality to find automatically different type files like Command, Routes.php. $discoverInComposer means whether to find them in Composer PSR-4 namespaces. --- a/app/Config/Modules.php
+++ b/app/Config/Modules.php
@@ -29,7 +29,7 @@ class Modules extends BaseModules
*
* @var bool
*/
- public $discoverInComposer = true;
+ public $discoverInComposer = false;
/**
* ----------------------------------------------------------------------------- a/app/Controllers/Home.php
+++ b/app/Controllers/Home.php
@@ -6,6 +6,6 @@ class Home extends BaseController
{
public function index()
{
- return view('welcome_message');
+ $faker = \Faker\Factory::create();
}
} |
|
In my understanding, discovery in Composer means scanning all known directories and files to Composer - not just limited to those that can be found in Commands/, Routes/, Filters/, etc.
As such based on the above, discovery in Composer means registering all classes (whether or not those classes are CodeIgniter modules). If I'm not correct, then the implementing logic in |
|
@paulbalandan Okay, you think the error in #5834 (comment) is not a bug, and no problem. And I don't agree with it. @MGatner Can you give me your opinion? |
|
I think I'm not understanding something in these threads. Tell me what I have wrong here:
|
|
Maybe Events was a bad example because they aren't actually classes. But take Services - I should be able to do this regardless of settings in Config\Modules: But if discovery is disabled in Config\Modules then this should fail: |
|
Let me also add: from Paul's original description that it seems certain there are some things currently wrong with the implementation. |
|
Modules' "Auto-Discovery"( |
|
I agree with 1 and 3.
About 2. |
|
I sent another PR #5849. |
|
I have sent a PR to fix what appears to be a bug in Autoloader: #5850 |
|
Discussion continued on the bugfix PR. @paulbalandan Can you weigh in there? I think deciding on that (whether it is indeed a bug) will clarify the rest of these. |
|
#5850 was merged. So close this. |
Description
Fixes #5818 (comment)
Since we only need Composer to register its PSR4 namespaces and classmaps into our internal autoloader, it should not be in the
spl_autoloadstack after as this messes withclass_existschecks. When our autoloader fails to find the file, PHP passes the search to the next autoloader, which is Composer. Our internal autoloader usesinclude_oncewhile Composer usesincludecausing the redeclaration error.Cannot write a unit test for this. To check manually using this repo:
"App\\": "app"in theautoload.psr4section in the root composer.jsoncomposer dump -oto regenerate the class map.'MyNameSpace' => APPPATH . 'ThirdParty/MyFolder'inConfig\Autoload::$psr4array.php spark make:command TeseCommand --namespace MyNameSpacephp spark. This will now error.php spark. No errors should appear.Checklist: