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

Вот как я автоматически загружаю все классы в папку 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/ (но не повторяется ли это?)?

Благодарю.

РЕДАКТИРОВАТЬ:

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

 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 { ... } 

Вы должны назвать свои классы, чтобы подчеркивание ( _ ) переводилось в разделитель каталога ( / ). Несколько фреймворков 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 () может быть определен только один раз.

редактировать

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

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

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

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

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

  • заявление/
    1. контроллеры /
      • Base.php
      • Factory.php
    2. модели /
      • 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, вы можете зарегистрировать несколько функций автозагрузки для загрузки файлов классов любым способом. То есть, вы могли бы поместить некоторые или все ваши классы в один каталог, или вы могли бы поместить некоторые или все ваши классы с именами в один файл . Очень гибкий 🙂

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


Иметь ввиду:

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

например: 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 ВОЗМОЖНО (потому что включение файла достаточно дорого)

Имея это в виду, я создал следующий сценарий:

 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 <- идет загрузчик
  • / Контроллер / … <- введите ur здесь
  • / Model / … <- или здесь и т. Д.
  • / …

Remeber:

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

Счастливое кодирование 😉


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

https://stackoverflow.com/a/5280353/626731 @alex хорошее решение, но не заставляйте вас классовые имена платить за плохие файловые структуры 😉 это задание для пространств имен

https://stackoverflow.com/a/5280510/626731 @ Mark-Eirich это работает, но его довольно противный / уродливый / медленный / жесткий [..] стиль, чтобы сделать это таким образом.

https://stackoverflow.com/a/5284095/626731 @tealou для решения своей проблемы это самый понятный подход 🙂 ..

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

https://stackoverflow.com/a/11866307/626731 @ Искариот .. вам, немного «вы-знай-фуфтинг-бенчмарк:

 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

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

https://stackoverflow.com/a/12548558/626731 @ Sunil-Kartikey https://stackoverflow.com/a/17286804/626731 @jurrien

НИКОГДА не зацикливайтесь на критически важных условиях! Не ищите файлы на os! – МЕДЛЕННЫЙ

https://stackoverflow.com/a/21221590/626731 @sagits .. намного лучше, чем Marks 😉

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

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

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

Я не уверен, что это лучшее решение или нет, но похоже, что он отлично работает …

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

Моя версия @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"); 

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

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

 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_controller_*.php и class_model_*.php , это должно работать нормально.

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

Образец кода. Работает 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; } } 

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

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

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

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

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

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

 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 вы можете получить свое имя.

Я использую это. В основном определите структуру папок (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;} } } к  //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;} } }