A
A
Anton Shamanov2020-09-28 19:57:35
PHP
Anton Shamanov, 2020-09-28 19:57:35

Extending/inheriting Composer's autoloader?

The task arose: after loading classes that inherit a certain interface, call a method to initialize their static properties.
The problem is that:

  1. Composer loader does not implement event mechanism
  2. the auto class name is generated when the package is installed (something like ComposerAutoloaderInitb1b2e8b29b5f68f94ccccac75d036f38) and, accordingly, it is not clear how best to organize inheritance

Options came to mind:
  1. Decorator wrapper: first load the Composer loader, then pass it to the facade and re-register autoloading to the facade
  2. generate class inheriting Composer loader: add event to composer.json
    "scripts": {"post-root-package-install": "Vendor\CodeGenerator\Autoloader::generate"}
    and in this method generate code

How best to implement? I'm considering any options.

Answer the question

In order to leave comments, you need to log in

3 answer(s)
A
Anton Shamanov, 2020-10-02
@SilenceOfWinter

as a result, having analyzed all the pitfalls, I came to the conclusion that the only viable option is to add your own loader after the composer one and inherit Composer\Autoload\ClassLoader.
Warning : In 7.4 OPCache has got class preloading which bypasses autoloading.

C
Constantine Karnaukhov, 2020-10-01
@genteelknight

In the comments to the question itself, they stuffed you with the most I don’t want, and in some places even on the case. But perhaps in your case there is no other way to do it. Personally, I'm for the first option. I myself had to patch the composer loader on a number of projects, something like this looks like:

<?php

use Composer\Autoload\ClassLoader;
use function Composer\Autoload\includeFile;

if (file_exists($composerAutoloaderPath = __DIR__ . '/../../../autoload.php')) {
    $patchedLoader = new class(require $composerAutoloaderPath) {
        private $loader;

        public function __construct(ClassLoader $loader)
        {
            $loader->unregister();
            $this->loader = $loader;
        }

        public function register($prepend = false): void
        {
            spl_autoload_register([$this, 'loadClass'], true, $prepend);
        }

        public function unregister(): void
        {
            spl_autoload_unregister([$this, 'loadClass']);
        }

        /**
         * Loads the given class or interface.
         * @param string $class The name of the class
         * @return bool True if loaded, null otherwise
         */
        public function loadClass($class): bool
        {
            if ($file = $this->loader->findFile($class)) {
                includeFile($file);

                // дополнительные патчи здесь

                return true;
            }

            return false;
        }
    };

    $patchedLoader->register(true);
}

Instead of vendor/autoload.php you include the file with your loader.
You can address this question to the developers of the packages that I include in my project.

At this point, it’s even interesting which packages impose the use of global state.

L
Leonid, 2020-10-01
@caballero

the task is not entirely clear, and in fig you need inheritance from the class that the composer generates dynamically,
if you need to perform some operation when loading, hang on composer events
if you need to load something additionally, write it in composer.json

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question