簡體   English   中英

來自不同文件夾的自動加載類

[英]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都會找到它。 它還允許我隨意調用我的課程。 我的代碼不需要類命名約定。

例如,您可以設置文件夾結構,如:

  • 應用/
    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();

編輯 - 關於自動加載的說明:

我的主要自動裝載機看起來像這樣:

// 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

我必須提一下“好”的自動加載腳本和代碼結構,所以請仔細閱讀以下內容


記住:

  • Classname ===文件名
  • 每個文件只有一個類

例如:Example.php包含

class Example {}
  • 命名空間===目錄結構

例如:/Path1/Path2/Example.php匹配

namespace Path1\Path2;
class Example {}
  • 應該是一個Root-Namespace來避免沖突

例如:/Path1/Path2/Example.php with root:

namespace APP\Path1\Path2;
class Example {}
  • 切勿使用手動定義的路徑或目錄列表,只需將加載程序指向最頂層的目錄即可
  • 保持加載程序AS FAST AS POSSIBLE(因為包含文件足夠昂貴)

考慮到這一點,我制作了以下腳本:

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 / ... < - 把你的東西放在這里
  • / 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 @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_*.phpclass_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM