Autoload classes from different folders

2019-01-07 03:20发布

This is how I autoload all the classes in my controllers folder,

# auto load controller classes
    function __autoload($class_name) 
    {
        $filename = 'class_'.strtolower($class_name).'.php';
        $file = AP_SITE.'controllers/'.$filename;

        if (file_exists($file) == false)
        {
            return false;
        }
        include ($file);
    }

But I have classes in models folder as well and I want to autoload them too - what should I do? Should I duplicate the autoload above and just change the path to models/ (but isn't this repetitive??)?

Thanks.

EDIT:

these are my classes file names in the controller folder:

class_controller_base.php
class_factory.php
etc

these are my classes file names in the model folder:

class_model_page.php
class_model_parent.php
etc

this is how I name my controller classes class usually (I use underscores and lowcaps),

class controller_base 
{
...
}

class controller_factory
{
...
}

this is how I name my model classes class usually (I use underscores and lowcaps),

class model_page 
    {
    ...
    }

    class model_parent
    {
    ...
    }

标签: php oop autoload
12条回答
放我归山
2楼-- · 2019-01-07 03:54

You should name your classes so the underscore (_) translates to the directory separator (/). A few PHP frameworks do this, such as Zend and Kohana.

So, you name your class Model_Article and place the file in classes/model/article.php and then your autoload does...

function __autoload($class_name) 
{
    $filename = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class_name)).'.php';

    $file = AP_SITE.$filename;

    if ( ! file_exists($file))
    {
        return FALSE;
    }
    include $file;
}

Also note you can use spl_autoload_register() to make any function an autoloading function. It is also more flexible, allowing you to define multiple autoload type functions.

If there must be multiple autoload functions, spl_autoload_register() allows for this. It effectively creates a queue of autoload functions, and runs through each of them in the order they are defined. By contrast, __autoload() may only be defined once.

Edit

Note : __autoload has been DEPRECATED as of PHP 7.2.0. Relying on this feature is highly discouraged. Please refer to PHP documentation for more details. http://php.net/manual/en/function.autoload.php

查看更多
疯言疯语
3楼-- · 2019-01-07 03:56

I see you are using controller_***** and model_***** as a class naming convention.

I read a fantastic article, which suggests an alternative naming convention using php's namespace.

I love this solution because it doesn't matter where I put my classes. The __autoload will find it no matter where it is in my file structure. It also allows me to call my classes whatever I want. I don't need a class naming convention for my code to work.

You can, for example, set up your folder structure like:

  • application/
    1. controllers/
      • Base.php
      • Factory.php
    2. models/
      • Page.php
      • Parent.php

Your classes can be set up like this:

<?php
namespace application\controllers;
class Base {...}

and:

<?php
namespace application\models;
class Page {...}

The autoloader could look like this (or see 'a note on autoloading' at the end):

function __autoload($className) {
    $file = $className . '.php';
    if(file_exists($file)) {
        require_once $file;
    }
}

Then... you can call classes in three ways:

$controller = new application\controllers\Base();
$model = new application\models\Page();

or,

<?php
use application\controllers as Controller;
use application\models as Model;

...

$controller = new Controller\Base();
$model = new Model\Page();

or,

<?php
use application\controllers\Base;
use application\models\Page;

...

$controller = new Base();
$model = new Page();

EDIT - a note on autoloading:

My main auto loader looks like this:

// autoload classes based on a 1:1 mapping from namespace to directory structure.
spl_autoload_register(function ($className) {

    # Usually I would just concatenate directly to $file variable below
    # this is just for easy viewing on Stack Overflow)
        $ds = DIRECTORY_SEPARATOR;
        $dir = __DIR__;

    // replace namespace separator with directory separator (prolly not required)
        $className = str_replace('\\', $ds, $className);

    // get full name of file containing the required class
        $file = "{$dir}{$ds}{$className}.php";

    // get file if it is readable
        if (is_readable($file)) require_once $file;
});

This autoloader is a direct 1:1 mapping of class name to directory structure; the namespace is the directory path and the class name is the file name. So the class application\controllers\Base() defined above would load the file www/application/controllers/Base.php.

I put the autoloader into a file, bootstrap.php, which is in my root directory. This can either be included directly, or php.ini can be modified to auto_prepend_file so that it is included automatically on every request.

By using spl_autoload_register you can register multiple autoload functions to load the class files any which way you want. Ie, you could put some or all of your classes in one directory, or you could put some or all of your namespaced classes in the one file. Very flexible :)

查看更多
beautiful°
4楼-- · 2019-01-07 04:02

I use this. Basically define your folder structure (MVC etc) as a constant in a serialised array. Then call the array in your autoload class. Works efficiently for me.

You could obviously create the folder array using another function but for MVC you may as well type it in manually.

For this to work you need to call your classes ...... class.classname.php

  //in your config file
    //define class path and class child folders
    define("classPath","classes");
    define("class_folder_array", serialize (array ("controller", "model", "view")));


  //wherever you have your autoload class
    //autoload classes
    function __autoload($class_name) {
    $class_folder_array = unserialize (class_folder_array);
    foreach ($class_folder_array AS $folder){
        if(file_exists(classPath."/".$folder.'/class.'.$class_name.'.php')){require_once classPath."/".$folder.'/class.'.$class_name.'.php';break;}
    }



    }
查看更多
Viruses.
5楼-- · 2019-01-07 04:03

My version of @Mark Eirich answer:

    function myload($class) {
      $controllerDir = '/controller/';
      $modelDir = '/model/';
      if (strpos($class, 'controller') !== false) {              
        $myclass = $controllerDir . $class . '.php';
      } else {
        $myclass = $modelDir . $class . '.inc.php';
      }
          if (!is_file($myclass)) return false;
          require_once ($myclass);

    }

    spl_autoload_register("myload");

In my case only controller class have the keyword in their name, adapt it for your needs.

查看更多
混吃等死
6楼-- · 2019-01-07 04:05

Here is my solution,

/**
     * autoload classes 
     *
     *@var $directory_name
     *
     *@param string $directory_name
     *
     *@func __construct
     *@func autoload
     *
     *@return string
    */
    class autoloader
    {
        private $directory_name;

        public function __construct($directory_name)
        {
            $this->directory_name = $directory_name;
        }

        public function autoload($class_name) 
        { 
            $file_name = 'class_'.strtolower($class_name).'.php';

            $file = AP_SITE.$this->directory_name.'/'.$file_name;

            if (file_exists($file) == false)
            {
                return false;
            }
            include ($file);
        }
    }

    # nullify any existing autoloads
    spl_autoload_register(null, false);

    # instantiate the autoloader object
    $classes_1 = new autoloader('controllers');
    $classes_2 = new autoloader('models');

    # register the loader functions
    spl_autoload_register(array($classes_1, 'autoload'));
    spl_autoload_register(array($classes_2, 'autoload'));

I'm not sure whether it is the best solution or not but it seems to work perfectly...

What do you think??

查看更多
Rolldiameter
7楼-- · 2019-01-07 04:08

Here's what I'd do:

function __autoload($class_name) {
    $class_name = strtolower($class_name);
    $filename = 'class_'.$class_name.'.php';

    if (substr($class_name, 0, 5) === 'model') {
        $file = AP_SITE.'models/'.$filename;
    } else $file = AP_SITE.'controllers/'.$filename;

    if (!is_file($file)) return false;
    include $file;
}

As long you name your files consistently, like class_controller_*.php and class_model_*.php, this should work fine.

查看更多
登录 后发表回答