26

I'm working on a project whereby I have the following file structure:

index.php
|---lib
|--|lib|type|class_name.php
|--|lib|size|example_class.php

I'd like to auto load the classes, class_name and example_class (named the same as the PHP classes), so that in index.php the classes would already be instantiated so I could do:

$class_name->getPrivateParam('name');

I've had a look on the net but can't quite find the right answer - can anyone help me out?

EDIT

Thanks for the replies. Let me expand on my scenario. I'm trying to write a WordPress plugin that can be dropped into a project and additional functionality added by dropping a class into a folder 'functionality' for example, inside the plugin. There will never be 1000 classes, at a push maybe 10?

I could write a method to iterate through the folder structure of the 'lib' folder, including every class then assigning it to a variable (of the class name), but didn't think that was a very efficient way to do it but it perhaps seems that's the best way to achieve what I need?

Sjwdavies
  • 4,079
  • 7
  • 38
  • 43

8 Answers8

36

Please, if you need to autoload classes - use the namespaces and class names conventions with SPL autoload, it will save your time for refactoring. And of course, you will need to instantiate every class as an object. Thank you.

Like in this thread: PHP Autoloading in Namespaces

But if you want a complex workaround, please take a look at Symfony's autoload class: https://github.com/symfony/ClassLoader/blob/master/ClassLoader.php

Or like this (I did it in one of my projects):

<?
spl_autoload_register(function($className)
{
    $namespace=str_replace("\\","/",__NAMESPACE__);
    $className=str_replace("\\","/",$className);
    $class=CORE_PATH."/classes/".(empty($namespace)?"":$namespace."/")."{$className}.class.php";
    include_once($class);
});
?>

and then you can instantiate your class like this:

<?
$example=new NS1\NS2\ExampleClass($exampleConstructParam);
?>

and this is your class (found in /NS1/NS2/ExampleClass.class.php):

<?
namespace NS1\NS2
{
    class Symbols extends \DB\Table
    {
        public function __construct($param)
        {
            echo "hello!";
        }
    }
}
?>
Community
  • 1
  • 1
Serge Velikan
  • 1,131
  • 15
  • 31
  • That looks ideal apart from it doesn't autoscan the file structure and instantiate the classes. Should I add your second code snipet around an iterator and then instantiate the class? – Sjwdavies Jul 23 '13 at 10:06
  • @Sjwdavies, the iteration through you file structure is on your own - it doesn't seems to be a needed part if you want to use namespaces (which is suggested). – Serge Velikan Jul 23 '13 at 10:11
  • @Sjwdavies, but sure, you **must** wrap the second code snippet with an file structure iterator if you want to automatically load all of your classes. But think and remember about script memory usage. – Serge Velikan Jul 23 '13 at 10:13
  • @Sjwdavies but if you really want to preload some class, I suggest you to add the word "auto" to its filenames (like Hello.class.auto.php), so you can easily handle its autoload in your wrapper. And you will not need to autoload non-static classes (like Hello2.class.php) – Serge Velikan Jul 23 '13 at 10:16
  • 1
    `And of course, you will need to instantiate every class as an object.` -> It is not clear to me if you see this as an advantage of disadvantage, and why. – Sebastian Mach Jun 25 '15 at 06:45
  • @phresnel, many things changed since 2013. I prefer to use Composer for every autoloading needs. Cheers – Serge Velikan Jun 25 '15 at 09:48
11

If you have an access to the command line, you can try it with composer in the classMap section with something like this:

{
    "autoload": {
        "classmap": ["yourpath/", "anotherpath/"]
    }
}

then you have a wordpress plugin to enable composer in the wordpress cli : http://wordpress.org/plugins/composer/

lilobase
  • 441
  • 3
  • 7
4
function __autoload($class_name) {
   $class_name = strtolower($class_name);
   $path       = "{$class_name}.php";
   if (file_exists($path)) {
       require_once($path);
   } else {
       die("The file {$class_name}.php could not be found!");
   }
}

UPDATE: __autoload() is deprecated as of PHP 7.2

Amir Hassan Azimi
  • 9,180
  • 5
  • 32
  • 43
3

http://php.net/manual/de/function.spl-autoload-register.php

spl_autoload_register(function ($class) {
    @require_once('lib/type/' . $class . '.php');   
    @require_once('lib/size/' . $class . '.php');
});
Daniel W.
  • 31,164
  • 13
  • 93
  • 151
  • I don't want to use that as I'll have to specify each and every file, which defeats the object of what I'm trying to do automatically. – Sjwdavies Jul 23 '13 at 09:34
  • Usually you include 1 main library file which includes all subclasses. You don't have to specify every single file - only the folder. How many folders do you have with main classes? Even if you have more folders, you can loop through just all of your folders with `readdir()` – Daniel W. Jul 23 '13 at 09:39
  • 1
    @DanFromGermany: I'd say you usually include one file, which is an autoloader instance, you configure it (register prefixes, suffixes, namespaces, include paths and so on), and _that_ class will load any classes that need loading when the time comes – Elias Van Ootegem Jul 23 '13 at 09:41
  • @EliasVanOotegem well that's what I mean. But you don't include 10000 single files – Daniel W. Jul 23 '13 at 09:42
  • Why is this the best way? – Sebastian Mach Jun 25 '15 at 06:46
  • 2 and a half year later I can say this is not a good approach lol go with composer :-) – Daniel W. Oct 29 '15 at 11:08
3

I have an example here that I use for autoloading and initiliazing.
Basically a better version of spl_autoload_register since it only tries to require the class file whenever you initializes the class.
Here it automatically gets every file inside your class folder, requires the files and initializes it. All you have to do, is name the class the same as the file.
index.php

<?php
require_once __DIR__ . '/app/autoload.php';

$loader = new Loader(false);

User::dump(['hello' => 'test']);

autoload.php

<?php
class Loader 
{

    public static $library;

    protected static $classPath = __DIR__ . "/classes/";

    protected static $interfacePath = __DIR__ . "/classes/interfaces/";

    public function __construct($requireInterface = true) 
    {
        if(!isset(static::$library)) {
            // Get all files inside the class folder
            foreach(array_map('basename', glob(static::$classPath . "*.php", GLOB_BRACE)) as $classExt) {
                // Make sure the class is not already declared
                if(!in_array($classExt, get_declared_classes())) {
                    // Get rid of php extension easily without pathinfo
                    $classNoExt = substr($classExt, 0, -4); 
                    $file = static::$path . $classExt;

                    if($requireInterface) {
                        // Get interface file
                        $interface = static::$interfacePath . $classExt;
                        // Check if interface file exists
                        if(!file_exists($interface)) {
                            // Throw exception
                            die("Unable to load interface file: " . $interface);
                        }

                        // Require interface
                        require_once $interface;
                        //Check if interface is set
                        if(!interface_exists("Interface" . $classNoExt)) {
                            // Throw exception
                            die("Unable to find interface: " . $interface);
                        }
                    }

                    // Require class
                    require_once $file;
                    // Check if class file exists
                    if(class_exists($classNoExt)) {
                        // Set class        // class.container.php
                        static::$library[$classNoExt] = new $classNoExt();
                    } else {
                        // Throw error
                        die("Unable to load class: " . $classNoExt);
                    }

                }
            }
        }
    }

    /*public function get($class) 
    {
        return (in_array($class, get_declared_classes()) ? static::$library[$class] : die("Class <b>{$class}</b> doesn't exist."));
    }*/
}

You can easily manage with a bit of coding, to require classes in different folders too.
Hopefully this can be of some use to you.

anttwuan
  • 101
  • 1
  • 7
  • Is good for large apps with many many many classes? Will it not hinder memory performance? –  Sep 18 '17 at 18:06
0

You can specify a namespaces-friendly autoloading using this autoloader.

<?php
spl_autoload_register(function($className) {
    $file = __DIR__ . '\\' . $className . '.php';
    $file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
    if (file_exists($file)) {
        include $file;
    }
});

Make sure that you specify the class file's location corretly.

Source

Supun Kavinda
  • 1,355
  • 14
  • 13
0
spl_autoload_register(function ($class_name) {
    $iterator = new DirectoryIterator(dirname(__FILE__));
    $files = $iterator->getPath()."/classes/".$class_name.".class.php";
    
    if (file_exists($files)) {
        include($files);
    } else {
       die("Warning:The file {$files}.class.php could not be found!");
    
    }
});
Murat Kezli
  • 187
  • 2
  • 5
0

do this in a file and called it anything like (mr_load.php) this were u put all your classes

spl_autoload_register(function($class){ 
     $path = '\Applicaton/classes/';
    $extension = '.php';
    $fileName = $path.$class.$extension;
    include $_SERVER['DOCUMENT_ROOT'].$fileName;
})

;

  • then create another file and include mr_load.php; $load_class = new BusStop(); $load_class->method()
Mayor
  • 1
  • 1