Composer Autoload Multiple Files in Folder
Asked Answered
B

3

28

I'm using composer in my latest project and mapping my function like this

"require": {
    ...
},
"require-dev": {
    ...
},
"autoload": {
    "psr-4": {
        ...
    },
    "files": [
        "src/function/test-function.php"
    ]
}

I imagine there will be a lot of files in a folder function, ex : real-function-1.php, real-function-2.php, etc. So, can composer call all the files in the folder function ? i lazy to use

"files": [
     "src/function/real-function-1.php",
     "src/function/real-function-2.php",
     ..,
     "src/function/real-function-100.php",
]

Is there any lazy like me...

Brigettebrigg answered 3/10, 2014 at 6:6 Comment(1)
That's the job of the autoload function. It will autoload the "main file" which would typicallu include a series of require statements. Here's an exampleBosnia
S
29

If you can't namespace your functions (because it will break a bunch of code, or because you can't use PSR-4), and you don't want to make static classes that hold your functions (which could then be autoloaded), you could make your own global include file and then tell composer to include it.

composer.json

{
    "autoload": {
        "files": [
            "src/function/include.php"
        ]
    }
}

include.php

$files = glob(__DIR__ . '/real-function-*.php');
if ($files === false) {
    throw new RuntimeException("Failed to glob for function files");
}
foreach ($files as $file) {
    require_once $file;
}
unset($file);
unset($files);

This is non-ideal since it will load every file for each request, regardless of whether or not the functions in it get used, but it will work.

Note: Make sure to keep the include file outside of your /real-function or similar directory. Or it will also include itself and turn out to be recursive function and eventually throw a memory exception.

Seabrook answered 3/10, 2014 at 7:5 Comment(0)
B
28

There's actually a better way to do this now without any custom code. You can use Composer's classmap feature if you're working with classes. If you're working with individual files that contain functions then you will have to use the files[] array.

{
    "autoload": {
        "classmap": ["src/", "lib/", "Something.php"]
    }
}
Bellew answered 12/4, 2018 at 17:56 Comment(0)
R
1

This whole process can be completely automated while still performing relatively well.

With the following package.json (note the absence of an autoload entry, you could however add others)

{
  "scripts": {
    "pre-autoload-dump": "\\MyComponentAutoloader::preAutoloadDump"
  }
}

And then...

<?php

class MyComponentAutoloader
{
    public static function preAutoloadDump($event): void
    {
        $optimize = $event->getFlags()['optimize'] ?? false;
        $rootPackage = $event->getComposer()->getPackage();

        $dir = __DIR__ . '/../lib'; // for example

        $autoloadDefinition = $rootPackage->getAutoload();
        $optimize
            ? self::writeStaticAutoloader($dir)
            : self::writeDynamicAutoloader($dir);
        $autoloadDefinition['files'][] = "$dir/autoload.php";
        $rootPackage->setAutoload($autoloadDefinition);
    }

    /**
     * Here we generate a relatively efficient file directly loading all
     * the php files we want/found. glob() could be replaced with a better
     * performing alternative or a recursive one.
     */
    private static function writeStaticAutoloader($dir): void
    {
        file_put_content(
            "$dir/autoload.php",
            "<?php\n" . 
            implode("\n", array_map(static function ($file) {
                return 'include_once(' . var_export($file, true) . ');';
            }, glob("$dir/*.php"))
        );
    }

    /**
     * Here we generate an always-up-to-date, but slightly slower version.
     */
    private static function writeDynamicAutoloader($dir): void
    {
        file_put_content(
            "$dir/autoload.php",
            "<?php\n\nforeach (glob(__DIR__ . '/*.php') as \$file)\n 
   include_once(\$file);"
        );
    }
}

Things to note:

  1. preAutoloadDump takes care of adding the autoload.php entrypoint to composer.
  2. autoload.php is generated every time the autoloader is dumped (e.g. composer install / composer update / composer dump-autoload)
  3. when dumping an optimised autoloader (composer dump-autoload --optimize), only the files found at that point will be loaded.
  4. you should also add autoload.php to .gitignore
Roundly answered 15/7, 2022 at 17:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.