Подтвердить что ты не робот

Автозагрузка классов из разных папок

Вот как я автоматически загружаю все классы в папку controllers,

# 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);
    }

Но у меня есть классы в папке models, и я тоже хочу их автозагрузить - что мне делать? Должен ли я дублировать автозагрузку выше и просто изменить путь к models/ (но не этот повторяющийся?)?

Спасибо.

EDIT:

это имена моих классов в папке контроллера:

class_controller_base.php
class_factory.php
etc

это мои имена файлов классов в папке модели:

class_model_page.php
class_model_parent.php
etc

так я обычно называю свой класс классов контроллеров (я использую символы подчеркивания и lowcaps),

class controller_base 
{
...
}

class controller_factory
{
...
}

так я обычно называю свой класс классов моделей (я использую символы подчеркивания и низкие символы),

class model_page 
    {
    ...
    }

    class model_parent
    {
    ...
    }
4b9b3361

Ответ 1

Вы должны назвать свои классы, чтобы подчеркивание (_) переводилось в разделитель каталога (/). Несколько фреймворков PHP делают это, например, Zend и Kohana.

Итак, вы называете свой класс Model_Article и помещаете файл в classes/model/article.php, а затем ваша автозагрузка делает...

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;
}

Также обратите внимание, что вы можете использовать spl_autoload_register(), чтобы сделать любую функцию функцией автозагрузки. Он также более гибкий, позволяя вам определять несколько функций типа автозагрузки.

Если необходимо несколько функций автозагрузки, для этого допускается spl_autoload_register(). Он эффективно создает очередь функций автозагрузки и проходит через каждый из них в том порядке, в котором они определены. Напротив, __autoload() может быть определен только один раз.

Edit

Примечание.. __autoload был отключен с PHP 7.2.0. Опираясь на эту функцию, очень не рекомендуется. Дополнительную информацию см. В документации по PHP. http://php.net/manual/en/function.autoload.php

Ответ 2

Я вижу, что вы используете controller_***** и model_***** как соглашение об именах классов.

Я прочитал фантастическую статью , в которой предлагается альтернативное соглашение об именах с использованием php namespace.

Мне нравится это решение, потому что неважно, где я помещаю свои классы. __autoload найдет его независимо от того, где он находится в моей файловой структуре. Это также позволяет мне называть мои классы тем, что я хочу. Мне не требуется соглашение об именах классов для моего кода.

Вы можете, например, настроить структуру вашей папки, например:

  • приложение /
    • Контроллеры /
      • Base.php
      • Factory.php
    • модели /
      • page.php
      • Parent.php

Ваши классы могут быть настроены следующим образом:

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

и

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

Автозагрузчик может выглядеть так (или увидеть "примечание об автозагрузке" в конце):

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

Затем... вы можете вызвать классы тремя способами:

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

или,

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

...

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

или,

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

...

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

EDIT - примечание об автозагрузке:

Мой главный автозагрузчик выглядит следующим образом:

// 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;
});

Этот автозагрузчик является прямым отображением имени класса в структуру каталогов 1:1; пространство имен - это путь к каталогу, а имя класса - имя файла. Таким образом, класс application\controllers\Base(), определенный выше, загрузит файл www/application/controllers/Base.php.

Я поместил автозагрузчик в файл bootstrap.php, который находится в моем корневом каталоге. Это можно либо включить напрямую, либо php.ini можно изменить на auto_prepend_file, чтобы он автоматически включался каждый запрос.

Используя spl_autoload_register, вы можете зарегистрировать несколько функций автозагрузки для загрузки файлов классов любым способом. Т.е. вы могли бы поместить некоторые или все ваши классы в один каталог или вы могли бы поместить некоторые или все ваши классы с именами в один файл. Очень гибкий:)

Ответ 3

Я должен упомянуть что-то о "хороших" сценариях автозагрузки и структуре кода, поэтому прочитайте следующее ВНИМАТЕЛЬНО


Держите в уме:

  • Имя класса === Имя файла
  • Только один класс для каждого файла

например: Example.php содержит

class Example {}
  • Пространство имен === Структура каталогов

например:/Path1/Path2/Example.php соответствует

namespace Path1\Path2;
class Example {}
  • ДОЛЖНО быть пространством имен корней, чтобы избежать столкновений.

например:/Path1/Path2/Example.php с корнем:

namespace APP\Path1\Path2;
class Example {}
  • НИКОГДА не используйте вручную определенные списки путей или каталогов, просто укажите загрузчик в самый верхний каталог
  • Держите загрузчик AS FAST AS POSSIBLE (потому что включение файла достаточно дорого)

С учетом этого я создал следующее script:

function Loader( $Class ) {
    // Cut Root-Namespace
    $Class = str_replace( __NAMESPACE__.'\\', '', $Class );
    // Correct DIRECTORY_SEPARATOR
    $Class = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, __DIR__.DIRECTORY_SEPARATOR.$Class.'.php' );
    // Get file real path
    if( false === ( $Class = realpath( $Class ) ) ) {
        // File not found
        return false;
    } else {
        require_once( $Class );
        return true;
    }
}

Где разместить это место.

  • /Loader.php < - идет загрузчик
  • /Controller/... < - введите ur здесь.
  • /Model/... < - или здесь и т.д.
  • /...

Примечание:

  • Если вы используете корневое пространство имен, загрузчик также должен находиться в этом пространстве имен
  • вы можете префикс $Class соответствовать вашим потребностям (controller_base {} → class_controller_base.php)
  • вы можете изменить __DIR__ на абсолютный путь, содержащий ваши файлы классов (например, "/var/www/classes" )
  • Если вы не используете пространства имен, все файлы должны находиться в одном каталоге вместе с загрузчиком (плохо!)

Счастливое кодирование; -)


Небольшой обзор в других ответах: ЭТО ТОЛЬКО МОЕ ПЕРСОНАЛЬНОЕ МНЕНИЕ - НЕ ПРЕДУСМОТРЕНО ПРЕДЛОЖЕНИЕ!

fooobar.com/questions/138681/... @alex хорошее решение, но не заставляйте вас классовые имена платить за плохие файловые структуры;-) это задание для пространств имен

fooobar.com/questions/138681/... @Mark-Eirich это работает, но его довольно неприятный/уродливый/медленный/жесткий [..] стиль, чтобы сделать это таким образом..

fooobar.com/questions/138681/... @tealou для решения своей проблемы, это самый понятный подход:-)..

fooobar.com/questions/138681/... @br3nt это отражает мою точку зрения, но, пожалуйста, (!).. не используйте strtr!!.. который подводит меня к:

fooobar.com/questions/138681/... @Искариот.. вам, немного" вы-знай-фуфтинг-бенчмарк:

Time        sprintf preg_replace strtr    str_replace v1 str_replace v2
08:00:00 AM 1.1334  2.0955       48.1423  1.2109         1.4819
08:40:00 AM 1.0436  2.0326       64.3492  1.7948         2.2337
11:30:00 AM 1.1841  2.5524       62.0114  1.5931         1.9200
02:00:00 PM 0.9783  2.4832       52.6339  1.3966         1.4845
03:00:00 PM 1.0463  2.6164       52.7829  1.1828         1.4981
Average     1.0771  2.3560       55.9839  1.4357         1.7237


Method         Times Slower (than sprintf)
preg_replace   2.19
strtr          51.97
str_replace v1 1.33
str_replace v2 1.6

Источник: http://www.simplemachines.org/community/index.php?topic=175031.0

Вопросы?.. (Но он на самом деле прав насчет полного пути, включая)

fooobar.com/questions/138681/... @Сунил-Картикей fooobar.com/questions/138681/... @jurrien

НИКОГДА не зацикливайтесь на критичной по времени среде! Не ищите файлы на os! - SLOW

fooobar.com/questions/138681/... @sagits.. намного лучше, чем Marks; -)

Ответ 4

function autoload($className)
{
//list comma separated directory name
$directory = array('', 'classes/', 'model/', 'controller/');

//list of comma separated file format
$fileFormat = array('%s.php', '%s.class.php');

foreach ($directory as $current_dir)
{
    foreach ($fileFormat as $current_format)
    {

        $path = $current_dir.sprintf($current_format, $className);
        if (file_exists($path))
        {
            include $path;
            return ;
        }
    }
}
}
spl_autoload_register('autoload');

Ответ 5

Вот мое решение,

/**
     * 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'));

Я не уверен, что это лучшее решение или нет, но кажется, что он отлично работает...

Как вы думаете?

Ответ 6

Моя версия ответа @Mark Eirich:

    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");

В моем случае только класс контроллера имеет ключевое слово в своем имени, адаптируйте его для ваших нужд.

Ответ 7

Вот что я сделал бы:

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;
}

Пока вы последовательно указываете свои файлы, например class_controller_*.php и class_model_*.php, это должно работать нормально.

Ответ 8

Самый простой ответ, который я могу вам дать, не записывая эти сложные коды и даже без использования пространства имен (если это вас смущает)

Пример кода. Работает 100%.

function __autoload($class_name){
$file = ABSPATH . 'app/models/' . $class_name . '.php';
if(file_exists($file)){
    include $file;
}else{
    $file = ABSPATH . 'app/views/' . $class_name . '.php';
    if(file_exists($file)){
        include $file;
    }else{
        $file = ABSPATH . 'app/controllers/' . $class_name . '.php';
        include $file;
    }
}

Я предполагаю, что логика объяснима сама собой. Привет, друг! Надеюсь, это поможет:)

Ответ 9

Каждый человек справляется и вставляет вещи из кода, который они вышли из Интернета (за исключением выбранного ответа). Все они используют String Replace.

Замена строки в 4 раза медленнее, чем strtr. Вы должны использовать его вместо этого.

Вы также должны использовать полные пути при включении классов с автозагрузкой, поскольку для решения этой проблемы требуется меньше времени.

Ответ 10

Функция

__ autoload() не должна использоваться, потому что она не охвачена. Вместо этого используйте spl_autoload(), spl_autoload_register(). __autoload() может загружать только один класс, но spl_autoload() может получить более 1 класса. И еще одно: в будущем __autoload() может устареть. Более подробную информацию можно найти на http://www.php.net/manual/en/function.spl-autoload.php

Ответ 11

Хотя этот script не имеет соглашения о названии, и этот поток уже немного стар, если кто-то ищет возможный ответ, это то, что я сделал:

function __autoload($name) {
    $dirs = array_filter(glob("*"), 'is_dir');

    foreach($dirs as $cur_dir) {
        dir_searcher($cur_dir, $name);
    }

}

function dir_searcher($cur_dir, $name) {

    if(is_file("$cur_dir/$name.php")) {
        require_once "$cur_dir/$name.php";
    }

    $dirs = array_filter(glob($cur_dir."/*"), 'is_dir');
    foreach($dirs as $cdir) {
        dir_searcher("$cdir", $name);
    }
}

не уверен, что он действительно оптимален, но он просматривает папки, читая рекурсивно. С помощью творческой функции str_replace вы можете получить свое имя.

Ответ 12

Я использую это. В основном определите структуру папок (MVC и т.д.) Как константу в сериализованном массиве. Затем вызовите массив в свой класс автозагрузки. Эффективно работает для меня.

Очевидно, вы можете создать массив папок с помощью другой функции, но для MVC вы также можете ввести его вручную.

Для этого вам нужно вызвать свои классы...... 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;}
    }



    }