Автозагрузка классов из разных папок
Вот как я автоматически загружаю все классы в папку 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
{
...
}
Ответы
Ответ 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
найдет его независимо от того, где он находится в моей файловой структуре. Это также позволяет мне называть мои классы тем, что я хочу. Мне не требуется соглашение об именах классов для моего кода.
Вы можете, например, настроить структуру вашей папки, например:
Ваши классы могут быть настроены следующим образом:
<?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;}
}
}