-1

I have trouble instantiating class by path in my PSR-0 autoloaded project. Structure is as follows:

| - src/
|    - Models/
|        - My_New_Model_Migration.php
|        - ...
|    SeederCommand.php
| - vendor/
|     - ...
| composer.json

And Composer autoloader:

"autoload": {
    "psr-0": {
        "" : [
            "src/"
        ]
    }
}

Not to get to much in SeederCommand class, it is basically a Doctrine/migrations class which is supposed to create a migration with up() and down() methods.

Inside the function responsible for generating those I have this part:

if (file_exists(__DIR__ . "/Models/{$model}_Migration.php")) {
    $class = "{$model}_Migration";
    $instantiated = new $class;
    ....
}

When echoing I notice that file indeed does exist, so this part is working as it should. When newing up the class however I am getting an error:

PHP Fatal error: Uncaught Error: Class '/var/www/html/.../src/Models/My_New_Model_Migration.php' not found in /var/www/html/.../src/SeederCommand.php:97

Since paths are correct, I presume the issue must be in way a PSR-0 autoloader works by parsing paths by underscore?

Is there some way around it?

EDIT:

This answer doesn't help me as it explains the 'why' of the autoloader story. I know how both PSR-0 and PSR-4 autoloaders work on the high level. I would like a way around the fact that autoloader wants a directory structure where there is none (and I don't want it introduced in this case).

EDIT2:

SeederCommand class requires autoload file:

require "../vendor/autoload.php"; 

I've tried doing a dump-autoload and renaming class to one without underscores and same thing happens, so I might have done something wrong with autoloading itself.

EDIT3:

I have tried newing up a class I renamed to a non-underscore version. For example newing up MyNewClass works, but My_New_Class throws an error.

Norgul
  • 4,613
  • 13
  • 61
  • 144

2 Answers2

1

Error while creating instance of new class

$class = __DIR__ . "/Models/{$model}_Migration.php";
$instantiated = new $class;

This is wrong because you cannot create an instance of a class by its file name like:

$instance = new /var/www/html/.../Class.php; // <-- wrong

Instead you need to use the class name and namespace:

$instance = new \Project\Namespace\Class;

So in your specific case it could be something like

$class = "\\Project\\Models\\".$model."_Migration";
// ^ depends on the real namespace and name of your migration classes
$instantiated = new $class;

PSR-0 and underscores

After reading the PSR-0 Standard again, I honestly think there is no way to achieve what you want (having a class name with underscore but no directory for it) while using PSR-0. The standard explicitly states:

Each _ character in the CLASS NAME is converted to a DIRECTORY_SEPARATOR.

Possible solution: Classmap autoloader

But you could use composer's classmap autoloader for those files instead:

This map is built by scanning for classes in all .php and .inc files in the given directories/files. You can use the classmap generation support to define autoloading for all libraries that do not follow PSR-0/4. To configure this you specify all directories or files to search for classes.

It could maybe look like that (but I was not able to test it):

"autoload": {
    "psr-0": {
        "" : [
            "src/"
        ]
    },
    "classmap": ["src/Models/"]
}
arkuuu
  • 619
  • 7
  • 23
1

You cannot have underscores in your classname, and not have them in the directory structure.

If your class is named Models_MyWhatever_Migration, because you dynamically add the string "MyWhatever" to the classname during migration, that class MUST be placed in src/Models/MyWhatever/Migration.php. You cannot have it in src/Models/MyWhatever_Migration.php.

If you want to keep the underscore as part of the filename, you have to switch to PSR-4 and use namespaces.

Sven
  • 69,403
  • 10
  • 107
  • 109