How to register path in autoload using a single in

2019-08-05 09:42发布

问题:

Sorry about the vague title, but I am trying to find some better alternatives to having to call an Autoloader class, and the register method multiple times, to map class paths as seen below.

$ClassLoader = new Autoloader\Loader(__DIR__.'/path/to/someclass');
$ClassLoader->register();

$ClassLoader = new Autoloader\Loader(_DIR__.'/path/to/anotherclass');
$ClassLoader->register();

$ClassLoader = new Autoloader\Loader(__DIR__.'/path/to/anotherclass');
$ClassLoader->register();

$ClassLoader = new Autoloader\Loader(__DIR__.'/path/to/anotherclass');
$ClassLoader->register();

$ClassLoader = new Autoloader\Loader(__DIR__.'/path/to/anotherclass');
$ClassLoader->register();

This goes on and on for about 50 lines, and I would like to know how I can handle the autoloading classes with simple few lines solution. I can obviously inject an array, to the constructor:

 $ClassLoader = new Autoloader\Loader( ['paths'=>[
                     '/path/to/class/', 
                     '/path/to/anotherclass',
                     '/path/to/anotherclass'
 ]);
 $ClassLoader->register();

But, I am not sure if this method is recommended at-least from OOP good practice point of view.

回答1:

Perhaps this is what you are looking for. For each directory that contains your classes run ::add.

namespace ClassLoader;

class Loader
{
    protected $directories = array();


    public function __construct()
    {
        spl_autoload_register([$this, 'load']);
    }

    public function add($dir)
    {
        $this->directories[] = rtrim($dir, '/\\');
    }

    private function load($class)
    {
        $classPath = sprintf('%s.php', str_replace('\\', '/', $class));

        foreach($this->directories as $dir) {
            $includePath = sprintf('%s/%s', $dir, $classPath);

            if(file_exists($includePath)) {
                require_once $includePath;
                break;
            }
        }
    }
}

$loader = new Loader();

$loader->add(__DIR__.'/src');
$loader->add(__DIR__.'/vendor');

use Symfony\Component\Finder\Finder;

$finder = new Finder(); 
// Included /var/www/test/vendor/Symfony/Component/Finder/Finder.php
// I put the Symfony components in that directory manually for this example.

print_r($finder);

It is effectively the same as with composer though, just less adaptive or performant.



回答2:

For this you can use Composer: https://getcomposer.org/download/

You will get a file called composer.phar. Place this in your project directory, then go to that directory on your command line.

Run php composer.phar init.

This will ask you a few questions which you can ignore, in the end you get a new file called composer.json

It should look something like this:

{
    "autoload": {
        "psr-0": { "": "src/" }
    },
    "require": {}
}

Add the autoload field, and replace src/ with the directory containing your classes. Make sure that directory exists.

Then run php composer.phar install.

This will create a directory called vendor. Inside this directory is a file called autoload.php.

Include this file in the bootstrap of your project, and all classes within your source directory will automatically be loaded in.



回答3:

Have you looked into spl_autoload_register function?

usage

// pre php 5.3
function my_autoloader($class) {
    include 'classes/' . $class . '.class.php';
}
spl_autoload_register('my_autoloader');

// Or, using an anonymous function as of PHP 5.3.0
spl_autoload_register(function ($class) {
    include 'classes/' . $class . '.class.php';
});

then place all your classes in "classes" folder and when you initialise them with the new keyword, they will be auto-included. Works with static classes also.

for example:

$myClassOb1 = new MyClass();
// will include this file: classes/MyClass.class.php

or

$email = Utils::formatEmail($emailInput);
// will include this file: classes/Utils.class.php


标签: php oop autoload