PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, January 24, 2022

[FIXED] PSR-4: Autoloader (composer) and extending namespaces ensuring fallback php

 January 24, 2022     composer-php, namespaces, php, psr-4     No comments   

Issue

I am having a problem with my namespace fallbacks and using PSR-4 loader in Composer.

What I am trying to do is this:

  1. Have a core which can overwritten / extended.
  2. The core is based off an interface.

The directory structure is like so:

site/app/View/Example.php
site/src/ACME/app/View/Example.php
site/src/ACME/app/Interface/View.php

I am not set on this configuration so if you have a better suggestion then go for it.

My composer json is like so for psr-4:

 "autoload": {
    "psr-4": {
         "ACME\\App\\Site\\" : "app/",
         "ACME\\App\\" : "src/AMCE/app/"
    }
}

I thought this would make ACME\App\Site\View fallback to ACME\App\View if the site one was not found (Note I haven't done the interface part yet...).

My code for site/app/View/Example.php is like so:

namespace ACME\App\Site\View;

class ViewExample extends View {

Which works, when I have site/app/View/View.php as well. That looks like:

namespace ACME\App\Site\View;

class View extends \ACME\App\View\View {

The site/src/app/View/View.php look like this:

namespace ACME\APP\View;

class View {

This one should use the interface (I haven't tried yet).

So what I really want to do is make it so I don't have to have site/app/View/View.php, and I don't have to have site/app/View/Example.php - it can use site/src/ACME/app/View/Example.php.

Sorry I'm new to namespaces so I may not of phrased it very well.

What I am getting at is I thought ACME\App\Site would fallback to ACME\App - it doesn't? Or I am doing it wrong? At the moment it needs all the files in place.


Solution

Edit: Turns out I was originally wrong, it is possible to get your example working with PSR-4! You just need to specify an array of directories for namespaces that can be loaded from different places.

Easy solution

{
    "autoload": {
        "psr-4": {
            "ACME\\App\\Site\\": ["app/", "src/ACME/app"],
            "ACME\\App\\": "src/ACME/app/"
        }
    }
}

Personally, I would rather name my namespaces more explicitly, see below.

Original Answer

The composer PSR-4 loader does not fall back when trying to load files that do not exist. It just fails immediately. Its flow looks like:

  1. \ACME\App\Site\View is not loaded
  2. Scan PSR-4 entries for matching namespaces
  3. Class name matches the namespace \ACME\App\Site (your first PSR-4 entry).
  4. Load file app/View.php
  5. File does not exist. Error.

It never goes back to step 3 and tries the next namespace.

So how do I fix it?

It looks like you want to separate your reusable library code from your site code. If that's the case, I would use separate namespaces. For example, use the ACME\Site namespace to hold your reusable code, and use ACME\MySiteName for your site-specific code. Then there will be no ambiguity, and composer will have no trouble loading your classes.

But I don't want to rearrange my namespaces!

Ok, that's fine, but you'll have to use a hack to get around your problem. Composer has a classmap loader, and you'll have to use that instead of the preferred PSR-4 loader.

{
    "autoload": {
        "classmap": ["app/", "src/"]
    }
}


Answered By - Justin Howard
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing