<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                > include 和 require 是PHP中引入文件的兩個基本方法。在小規模開發中直接使用 include 和 require 沒喲什么不妥,但在大型項目中會造成大量的 include 和 require 堆積。這樣的代碼既不優雅,執行效率也很低,而且維護起來也相當困難。 > 為了解決這個問題,部分框架會給出一個引入文件的配置清單,在對象初始化的時候把需要的文件引入。但這只是讓代碼變得更簡潔了一些,引入的效果仍然是差強人意。PHP5 之后,隨著 PHP 面向對象支持的完善,__autoload 函數才真正使得自動加載成為可能。 ## 1. __autoload 實現自動加載最簡單的方式就是使用 __autoload 魔術方法。當需要使用的類沒有被引入時,這個函數會在PHP報錯前被觸發,未定義的類名會被當作參數傳入。至于函數具體的邏輯,這需要用戶自己去實現。 在類的實例化過程中,系統所做的工作大致是這樣的: ```php /* 模擬系統實例化過程 */ function instance($class) { // 如果類存在則返回其實例 if (class_exists($class, false)) { return new $class(); } // 查看 autoload 函數是否被用戶定義 if (function_exists('__autoload')) { __autoload($class); // 最后一次引入的機會 } // 再次檢查類是否存在 if (class_exists($class, false)) { return new $class(); } else { // 系統:我實在沒轍了 throw new Exception('Class Not Found'); } } ``` 明白了 __autoload 函數的工作原理之后,那就讓我們來用它去實現自動加載。 test.php文件如下 ```php <?php // __autoload,當類不存在時觸發該函數,參數是類名 function __autoload($class){ $file = $class.'.php'; if(file_exists($file)){ include($file); //載入類文件 } } $c = new Hello(); $c->test(); ?> ``` Hello.php文件如下 ``` <?php class Hello{ function test(){ echo 'test function!'; } } ?> ``` 當運行`php test.php`時,系統找不到Hello類,觸發__autoload函數include類文件。 ## 2. spl_autoload_register > spl_autoload_register 函數的功能就是把傳入的函數(參數可以為回調函數或函數名稱形式)注冊到 `SPL __autoload` 函數隊列中,并移除系統默認的 `__autoload()` 函數。 即> 一旦調用 `spl_autoload_register()` 函數,當調用未定義類時,系統就會按順序調用注冊到 `spl_autoload_register()` 函數的所有函數,而不是自動調用 `__autoload()` 函數。 即spl_autoload_register可以注冊多個函數 spl_autoload_register(funa()); spl_autoload_register(funb()); spl_autoload_register(func()); 例如將上面的hello.php加上命名空間 `namespace app;`,然后就可以用這個函數映射機制去加載 ``` spl_autoload_register(function ($class) { /* 限定類名路徑映射 */ $class_map = array( // 限定類名 => 文件路徑 'app\\Hello' => './Hello.php', ); /* 根據類名確定文件名 */ $file = $class_map[$class]; /* 引入相關文件 */ if (file_exists($file)) { include $file; } }); ``` 這里我們使用了一個數組去保存類名與文件路徑的關系,這樣當類名傳入時,自動加載器就知道該引入哪個文件去加載這個類了。 但是一旦文件多起來的話,映射數組會變得很長,這樣的話維護起來會相當麻煩。如果命名能遵守統一的約定,就可以讓自動加載器自動解析判斷類文件所在的路徑。接下來要介紹的PSR-4 就是一種被廣泛采用的約定方式。 ## 3. psr-4 PSR-4 是關于由文件路徑自動載入對應類的相關規范,規范規定了一個完全限定類名需要具有以下結構: \<頂級命名空間>(\<子命名空間>)*\<類名> 如果繼續拿上面的例子打比方的話,頂級命名空間相當于公司,子命名空間相當于職位,類名相當于人名。那么李彥宏標準的稱呼為 "百度公司 CEO 李彥宏"。 PSR-4 規范中必須要有一個頂級命名空間,它的意義在于表示某一個特殊的目錄(文件基目錄)。子命名空間代表的是類文件相對于文件基目錄的這一段路徑(相對路徑),類名則與文件名保持一致(注意大小寫的區別)。 舉個例子:在全限定類名 \app\view\news\Index 中,如果 app 代表 C:\Baidu,那么這個類的路徑則是 C:\Baidu\view\news\Index.php 我們就以解析 \app\view\news\Index 為例,編寫一個簡單的 Demo: ```php $class = 'app\view\news\Index'; /* 頂級命名空間路徑映射 */ $vendor_map = array( 'app' => 'C:\Baidu', ); /* 解析類名為文件路徑 */ $vendor = substr($class, 0, strpos($class, '\\')); // 取出頂級命名空間[app] $vendor_dir = $vendor_map[$vendor]; // 文件基目錄[C:\Baidu] $rel_path = dirname(substr($class, strlen($vendor))); // 相對路徑[/view/news] $file_name = basename($class) . '.php'; // 文件名[Index.php] /* 輸出文件所在路徑 */ echo $vendor_dir . $rel_path . DIRECTORY_SEPARATOR . $file_name; ``` 通過這個 Demo 可以看出限定類名轉換為路徑的過程。那么現在就讓我們用規范的面向對象方式去實現自動加載器吧。 首先我們創建一個文件 Index.php,它處于 \app\mvc\view\home 目錄中: ```php namespace app\mvc\view\home; class Index { function __construct() { echo '<h1> Welcome To Home </h1>'; } } ``` 接著我們在創建一個加載類(不需要命名空間),它處于 \ 目錄中: ```php class Loader { /* 路徑映射 */ public static $vendorMap = array( 'app' => __DIR__ . DIRECTORY_SEPARATOR . 'app', ); /** * 自動加載器 */ public static function autoload($class) { $file = self::findFile($class); if (file_exists($file)) { self::includeFile($file); } } /** * 解析文件路徑 */ private static function findFile($class) { $vendor = substr($class, 0, strpos($class, '\\')); // 頂級命名空間 $vendorDir = self::$vendorMap[$vendor]; // 文件基目錄 $filePath = substr($class, strlen($vendor)) . '.php'; // 文件相對路徑 return strtr($vendorDir . $filePath, '\\', DIRECTORY_SEPARATOR); // 文件標準路徑 } /** * 引入文件 */ private static function includeFile($file) { if (is_file($file)) { include $file; } } } ``` 最后,將 Loader 類中的 autoload 注冊到 spl_autoload_register 函數中: ```php include 'Loader.php'; // 引入加載器 spl_autoload_register('Loader::autoload'); // 注冊自動加載 new \app\mvc\view\home\Index(); // 實例化未引用的類 /** * 輸出: <h1> Welcome To Home </h1> */ ``` 示例中的代碼其實就是 ThinkPHP 自動加載器源碼的精簡版,它是 ThinkPHP 5 能實現惰性加載的關鍵。 至此,自動加載的原理已經全部講完了,如果有興趣深入了解的話,可以參考 ThinkPHP 源碼。 文件地址:\thinkphp\library\think\Loader.php 原文地址:https://www.cnblogs.com/woider/p/6443854.html?_blank 有改動~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看