Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why specify the namespace when using psr-4 autoloading with Composer?

I'm a little confused with how I should be using psr-4 autoloading in Composer. Let's say I've got a folder structure like this:

/
|- Core/
|   - Router.php
|- App/
|   - Models
|       User.php
|- composer.json

Basically, in the project root: composer.json; a Core folder containing a Router php class; an App folder containing a Models folder that contains a User class.

The Router class looks like this:

<?php
namespace Core;

class Router {
}

and the Users class looks like this:

<?php
namespace App\Models;

class User {
}

So I can autoload these classes using the Composer psr-4 autoloader, I can do this in composer.json:

{
    "autoload": {
        "psr-4": {
            "Core\\": "Core",
            "App\\Models\\": "App/Models"
        }
    }
}

So I can then use the classes without requiring them (after running composer dump-autoload) like this:

$router = new Core\Router();
$user = new App\Models\User();

which works with no problems.

However, I can also do this in composer.json:

{
    "autoload": {
        "psr-4": {
            "": ""
        }
    }
}

which, according to the documentation is a fallback directory where any namespace can be, relative to the root. So by having this "empty" entry in the composer autoloader, which I believe says "starting in the root, look in any directory for a class in any namespace", I can autoload any of my classes if I follow the correct folder naming / namespace structure.

So my question is, why would I do the former if the latter works and is much simpler? Is it a performance thing? Or is there another reason?

like image 991
Dave Hollingworth Avatar asked Mar 22 '16 15:03

Dave Hollingworth


People also ask

What's the purpose of PSR 4 autoloading?

Overview. This PSR describes a specification for autoloading classes from file paths. It is fully interoperable, and can be used in addition to any other autoloading specification, including PSR-0. This PSR also describes where to place files that will be autoloaded according to the specification.

What is PSR 4 autoloading standard laravel?

The PSR-4 autoloading standard requires the fully qualified class name to match the filesystem path, and is case-sensitive. The namespace prefix is mapped by the psr-4 option in your composer. json .

What is Composer json?

composer. json is a JSON file placed in the root folder of PHP project. Its purpose is to specify a common project properties, meta data and dependencies, and it is a part of vast array of existing projects. In most ways, it is a counterpart to . NET project file.

What is composer generated autoloader definition?

Autoloading: The classmap DirectiveFor each file, Composer will make a list of classes that are contained in that file, and whenever one of those classes is needed, Composer will autoload the corresponding file. Let's quickly revise the composer. json file to demonstrate the classmap autoloader. 1.


2 Answers

Why shouldn't you always do "psr-4": {"": ""}?

Reason 1: It cost performance. The definition says that for EVERY class that needs autoloading, Composer should look into the root directory. These classes are not only the ones in your package, but ALL other classes as well.

Composer tries to optimizes this effort a bit by remembering fruitless searches, but this only pays if you load another class with the same prefix.

Reason 2: The essence of PSR-4 is that you don't have to have the whole namespace path mapped to a directory path. Assuming that you have a package which deals with a very specific group of classes like \Vendor\Template\Escaping\Output\*, and nothing else (having small packages makes it easier to reuse them without adding too much code), you can have them in src/Vendor/Template/Escaping/Output/AnyClass.php and define

"psr-4": {
        "\\Vendor\\Template\\Escaping\\Output\\": "src/Vendor/Template/Escaping/Output/"
}

You can also put the class into src/AnyClass.php and define

"psr-4": {
        "\\Vendor\\Template\\Escaping\\Output\\": "src/"
}

And this shortens the directory path significantly, marginally improving speed (I think - have no figures though), but mostly improving developing the thing due to less opening of empty folders.

Having both a Core namespace and an App namespace in the same package makes me suspicious: Why isn't there one package for each of these?

like image 54
Sven Avatar answered Sep 26 '22 00:09

Sven


Usually you only have one folder for your own project when using composer. Then you only need to specify one namespace.

Consider that you would rearrange your file structure to

/
|- lib/
|   - Core/
|      - Router.php
|   - App/
|      - Models
|          User.php
|- composer.json

and change your composer.json to

{
    "autoload": {
        "psr-4": {
            "MyApp\\": "lib/"
        }
    }
}

then you only have one specified namespace and you dont need to add any further namespaces. You can call your classes like this:

$router = new \MyApp\Core\Router;
$user   = new \MyApp\App\Models\User;

or like this:

namespace MyApp;
$router = new Core\Router;
$user   = new App\Models\User;
like image 39
Adam Avatar answered Sep 23 '22 00:09

Adam