PSR4 auto load without composer
Asked Answered
S

3

11

I have one package in a project which is autoloaded using composer and composer.json entry is as follows :

 "autoload": {
      "psr-4": {
        "CompanyName\\PackageName\\": "packages/package-folder/src/"
    }
  }

Now I am copying this over to another project which is not using composer. How can I autoload this same package there ?

Subduct answered 19/9, 2016 at 10:52 Comment(5)
If you have a composer.json file, you can only use composer to find the packages and load them into your project.Insensitive
But this is not located in composer repository. Its a custom repository and is autoloaded using autoload functionality of composer.Subduct
You can try autoloading it directly: php.net/manual/en/function.autoload.phpInsensitive
But how can I do it for all the classes ? In composer, I am giving the folder path. Here I need to do it recursively ?Subduct
You could make it work with custom repository (zip, git etc.). Please see the following documentation: getcomposer.org/doc/05-repositories.mdAudryaudrye
H
26

You have to read the composer and load the classes yourself for each namespaces defined into the composer.json.

Here is how :

function loadPackage($dir)
{
    $composer = json_decode(file_get_contents("$dir/composer.json"), 1);
    $namespaces = $composer['autoload']['psr-4'];

    // Foreach namespace specified in the composer, load the given classes
    foreach ($namespaces as $namespace => $classpaths) {
        if (!is_array($classpaths)) {
            $classpaths = array($classpaths);
        }
        spl_autoload_register(function ($classname) use ($namespace, $classpaths, $dir) {
            // Check if the namespace matches the class we are looking for
            if (preg_match("#^".preg_quote($namespace)."#", $classname)) {
                // Remove the namespace from the file path since it's psr4
                $classname = str_replace($namespace, "", $classname);
                $filename = preg_replace("#\\\\#", "/", $classname).".php";
                foreach ($classpaths as $classpath) {
                    $fullpath = $dir."/".$classpath."/$filename";
                    if (file_exists($fullpath)) {
                        include_once $fullpath;
                    }
                }
            }
        });
    }
}

loadPackage(__DIR__."/vendor/project");

new CompanyName\PackageName\Test();

Of course, I don't know the classes you have in the PackageName. The /vendor/project is where your external library was cloned or downloaded. This is where you have the composer.json file.

Note: this works only for psr4 autoload.

EDIT : Adding support for multiple classpaths for one namespace

EDIT2 : I created a Github repo to handle this code, if anyone wants to improve it.

Huambo answered 29/9, 2016 at 15:57 Comment(0)
E
9

Yes, this question is 6months old, however I just used the following. I just found the following solution to the problem. I just locally ran the command composer dump-autoload -o in my project folder. After that I simply had to upload the contents of ./vendor/composer folder and the /vendor/autoload.php to the server and it worked again. This is helpful in case you cannot run composer on the server.

Emanuele answered 8/4, 2017 at 18:7 Comment(2)
This it not really the same question. The OP asked to handle autoload from the composer.json without having composer at all.Huambo
This is still a useful and relevant comment. Because I was about to face this issue in a plugin I develop.My search brought me exactly here. And while your answer is correct and valid, so is this answer. Because when a user installs my plugin and cant run composer, the autoload still has to work. So knowing I can do this locally and deploy it without worry, helps a lot.Bracknell
V
5

I am not a fan of Composer for many reasons. 1st reason shared hosting services do not offer composer as a package therefor it makes it harder to deliver low budget applications or simple MVC custom frameworks. Here is a work around that is compliant with PSR4 standards.

Assuming you add this auto-load method in a file in the root directory and that we are auto-loading classes for everything inside a folder called "src" here is how to archive this.

define('ROOT', dirname(__DIR__));
define('SLASH', DIRECTORY_SEPARATOR);

spl_autoload_register(function ($className) 
{
    $fileName = sprintf("%s%ssrc%s%s.php", ROOT, SLASH, SLASH, str_replace("\\", "/", $className));

    if (file_exists($fileName)) 
    {
        require ($fileName);
    } 
    else 
    {
        echo "file not found {$fileName}";
    }
});

now in every file you should add a namespace and if you have a dependency the use. here is a basic example in

namespace myapp;
use Core\Example;

Also, all your folders inside src should start with a capital letter in my example.

and done. Cheers @jerryurenaa

Verge answered 13/9, 2020 at 21:11 Comment(4)
I asked three years ago. Forgot the scenario . Anyway thanks for answeringSubduct
"1st reason shared hosting services do not offer composer as a package" - you absolutely don't need to install Composer on your server to use itTaffeta
@NicoHaase, good luck running the composer dump-autoload command.Verge
@Verge I have never had the need to do this on any of my production systems. This is done during building the application on my CI servers, and the code is never modified on the production system. What would be the need to dump the autoloader on production?Taffeta

© 2022 - 2024 — McMap. All rights reserved.