composer: Autoloading not working in child threads on PHP5.6 or higher
I’m starting a project that uses pthreads to do jobs in parallel. The method \Thread::run
is executed in a new context and don’t share the autoload previously included at very begining of the script. The solution for that is to require vendor/autoload.php
inside that method and the thread can make use of composer autoloader normally. I’m using PHP5.6 and for some reason the composer can’t load the classes needed in the \Thread::run
context. Inspecting the file vendor/composer/autoload_real.php
I realize that composer tries to load the configuration from vendor/composer/autoload_static.php
file if the PHP_VERSION_ID
is greather than 50600 and HHVM_VERSION
constant is not defined. Forcing false
to this verification the composer will load the configuration from the autoload_[namespaces|psr4|classmap].php
files normally and everything works like a charm.
class MyThread extends \Thread
{
public function run()
{
register_shutdown_function(function () {
var_dump(error_get_last());
});
require 'vendor/autoload.php';
$obj = new My\Namespace\Class;
}
}
// sample.php
require 'vendor/autoload.php';
$thread = new MyThread;
$thread->start() && $thread->join();
Output of php -v
PHP 5.6.22 (cli) (built: Jun 10 2016 03:26:22)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
Output of composer -V
Composer version 1.2-dev (cc793eff6f8b4757e15f9901908314c08be89a4e) 2016-05-05 23:28:45
The method that gets the loader from autoload_static.php
file.
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit3b449be9b69a18112bf0b6d553b917f8', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit3b449be9b69a18112bf0b6d553b917f8', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit3b449be9b69a18112bf0b6d553b917f8::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
return $loader;
}
I’m suspecting that the problem leaves on this method from ComposerStaticInit3b449be9b69a18112bf0b6d553b917f8
class. For some reason setting the properties of $loader
object is not working.
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit3b449be9b69a18112bf0b6d553b917f8::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit3b449be9b69a18112bf0b6d553b917f8::$prefixDirsPsr4;
}, null, ClassLoader::class);
}
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 23 (8 by maintainers)
Hi @gintares,
I’m passing the composer autoloader instance as a dependency of the threads.
Of course this isn’t the best way to autoload classes in a threaded context but works properly until the pthread extension maintainers gets the this issue done.
Hi @alcohol. Exactly what I’m suspecting. A workaround to this is inject the intance of
ClassLoader
into MyThread and call$this->loader->register()
inside therun()
method.