Вот как я автоматически загружаю все классы в папку 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
найдет его независимо от того, где он находится в моей файловой структуре. Это также позволяет мне называть мои классы тем, что я хочу. Для моего кода мне не требуется соглашение об именах классов.
Например, вы можете настроить структуру папок, например:
Ваши классы можно настроить следующим образом:
<?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 {}
Имея это в виду, я создал следующий сценарий:
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; } }
Где поместить его ..
Remeber:
Счастливое кодирование 😉
Небольшой обзор в других ответах: ЭТО ТОЛЬКО МОЕ ЛИЧНОЕ МНЕНИЕ – НЕ ПРЕДУСМОТРЕНО!
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;} } }