[英]Composer autoload - How to fetch classes, traits, interfaces from different folders?
[英]Autoload classes from different folders
這是我如何自動加載我的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/
的路徑models/
(但這不是重復?)?
謝謝。
編輯:
這些是我在控制器文件夾中的類文件名:
class_controller_base.php
class_factory.php
etc
這些是我在模型文件夾中的類文件名:
class_model_page.php
class_model_parent.php
etc
這就是我通常命名我的控制器類的方法(我使用下划線和低位),
class controller_base
{
...
}
class controller_factory
{
...
}
這就是我通常命名我的模型類的方法(我使用下划線和lowcaps),
class model_page
{
...
}
class model_parent
{
...
}
我看到你使用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();
編輯 - 關於自動加載的說明:
我的主要自動裝載機看起來像這樣:
// 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,您可以注冊多個自動加載功能,以任何方式加載類文件。 即,您可以將一些或所有類放在一個目錄中,或者可以將一些或所有命名空間類放在一個文件中 。 非常靈活:)
您應該為類命名,以便下划線( _
)轉換為目錄分隔符( /
)。 一些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()只能定義一次。
編輯
注意:自PHP 7.2.0起,__ autoload已被棄用。 非常不鼓勵依賴此功能。 有關更多詳細信息,請參閱PHP文檔。 http://php.net/manual/en/function.autoload.php
我必須提一下“好”的自動加載腳本和代碼結構,所以請仔細閱讀以下內容
記住:
例如:Example.php包含
class Example {}
例如:/Path1/Path2/Example.php匹配
namespace Path1\Path2;
class Example {}
例如:/Path1/Path2/Example.php with root:
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 @Iscariot ..給你,一點點“你知道廢話基准:
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");
在我的情況下,只有控制器類在其名稱中包含關鍵字,根據您的需要進行調整。
最簡單的答案我可以給你,而不必寫下那些復雜的代碼,甚至不使用命名空間(如果這讓你感到困惑)
示例代碼。 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;
}
}
我猜邏輯本身是可以解釋的。 隊友的歡呼聲! 希望這可以幫助 :)
這是我要做的:
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
,這應該可以正常工作。
每個人都在從他們從互聯網上下載的代碼中處理和粘貼事物(除了選定的答案)。 它們都使用String Replace。
字符串替換比strtr慢4倍。 你應該使用它。
在包含具有自動加載功能的類時,您還應該使用完整路徑,因為操作系統解析路徑的時間較短。
__autoload()函數不應該使用,因為它沒有被激怒。 請改用spl_autoload(),spl_autoload_register()。 __autoload()只能加載一個類,但spl_autoload()可以獲得多個類。 還有一件事,將來__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);
}
}
不確定它是否真的最佳,但它通過遞歸讀取dir搜索文件夾。 借助創新的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;}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.