你所不知道 ❌ PHP 自動加載

前言

不少的小夥伴在,學習 PHP 的時候最先面對的問題之一就是 requireincluderequire_onceinclude_once 的相愛相殺。php

在瞭解了它們相愛相殺的故過後,每每就開始使用起了框架。框架當然是幹活的好工具,可是你知道你平時 new 一個新類的時候,發生了什麼嗎?有想過爲何咱們 遵循規範 就會自動的幫咱們作好一切的加載嗎? 讓咱們一切來探索發現其中的奧祕。git

時間線

蒸汽時代

PHP 代碼的頂部你是否是常常看到這樣的代碼。github

require 'lionis.php';
require 'is.php';
require 'cool.php';

若是隻是引入幾個 PHP 腳本,那還能夠接受。那引入成千上萬個腳本的時候,爆炸是在所不免的。若是對一個腳本改了個名字,還須要對引入改腳本的每一個腳本更名,能不爆炸嗎?連打出這段話都怎麼繞。json

電氣時代

PHP 電氣時代,開始出現了 __autoloadspl_autoload_register 函數註冊自定義的自動加載策略。數組

通俗的來講,__autoloadspl_autoload_register 是一個 殺手組織,他們會去僱傭 各國殺手 (函數)。當咱們想搞定某我的的時候(new),只須要提供名字(類名),剩下的 殺手 會幫咱們搞定的。微信

__autoload

PHP 5 開始提供這個函數 傳送門。當你使用的 找不到的時候,它把類名當成參數扔進這個函數。composer

<?php
// Lionis.php
class Lionis {
    public function __construct() {
        echo '歐耶耶, 我就是 Lionis';
    }
}
<?php
// index.php
function __autoload($classname) {
    $filename = './' . $classname . '.php';
    require_once $filename;
}

$lionis = new Lionis();

輸出框架

歐耶耶, 我就是 Lionis
spl_autoload_register

若是咱們 項目 很大很老又或者你是一個 愛折騰 的少先隊員,須要引入的東西有不同的規範,這時候若是都放在 __autoload 函數裏,這個函數立刻就會膨脹的。並且 __autoload 是全局惟一的,若是被人佔用了,可能會致使錯誤。(欲使一我的滅亡,必將先使其膨脹。)函數

PHP 5.1.2 開始提供這個函數 傳送門,註冊給定的函數做爲 __autoload 的實現。因此,咱們看一些框架或插件在本身使用的時候,爲了兼容可能會出現 function_exists(spl_autoload_register)工具

<?php
function lionisIsCoolFind($classname) {
    require './' . $classname . '.php';
}

// 函數
spl_autoload_register('lionisIsCoolFind');

// 匿名函數
spl_autoload_register(function($require) {
    require './' . $classname . '.php';
});

// 類中的函數
spl_autoload_register(array('Lionis', 'loadClass'));

歐耶,這下咱們能夠寫不少不一樣的自動加載函數了。

信息時代

師傅當心,前面有妖氣! 。若是咱們每一個人都本身實現一套自動加載的方法,每一個PHP 組件框架都使用獨特的自動加載器,並且每一個框架使用不一樣的邏輯加載PHP類、接口和性狀。

那當咱們使用一些第三方框架的時候,還須要去弄清楚引導文件中的 自動加載器,那樣是有多和 時間 過不去呢。 PHP-FIG 認識到了這個問題了,推薦使用 PSR-4 規範,來促進組件之間的 互操做性,這樣咱們就可使用一個自動加載器了。

PSR-4 規範

利用命名空間的前綴和文件系統中的目錄對應起來。

映射關係爲

namespace    => filePath
\Lionis\Cool => cool

帶有命名空間的類

<?php
// 該文件爲 cool/Real.php
namespace \Lionis\Cool;

class Real {
}

建立一個對象

<?php
// 該文件爲 index.php

$lionis = new \Lionis\Cool\Real;

這個時候,按照 PSR-4 的規範,自動加載器應該去加載 cool/ 目錄下的 Real.php

不對!那這樣不是還要本身去實現 自動加載器 嘛,否則怎麼 無中生有 出現 自動加載器 呢?難道官方 內置 了?

out 了吧,咱們可使用依賴管理器 composer 來生成 PSR-4 自動加載器。你可能會疑問,那個人舊項目沒有遵循 PSR-4 規範怎麼辦?嘿嘿,讓咱們來探索發現一下 composer 是怎麼解決這個問題的吧。

Composer

哦吼吼,咱們此次的重點在與探究自動加載,因此 composer 的安裝和使用等,就不去討論了。

composer 自動加載設置了 4種 加載方式

  • PSR-0
  • PSR-4
  • classmap
  • files

PSR-0

要求命名空間和目錄層層對應,且可使用 _ 做爲路徑分隔符,可是這會致使目錄結果變得過深。

composer 執行 install 等操做時,composer 會把文件中的配置存儲在 vendor/composer/autoload_psr0.php文件中的返回數組中。

例如:定義了Very\Good=>vendor\Lionis\IsReal\Cool,在調用 use Very\Good\Love\SomeClass,PSR-0 加載的實際目錄爲 vendor/Lionis/IsReal/Cool/Very/Good/Love/SomeClass.php。

對吧,這簡直深得嚇人,因此 PSR-0 被官方廢除了。可是一些主流的框架已經實現了 PSR-0,爲了向下兼容仍是要實現 PSR-0

composer.json配置:

"autoload": {
    "psr-0": {
        "Very\\Good": "vendor\Lionis\IsReal\Cool"
    }
}

PSR-4

PSR-4 是如今比較推薦的方法,用於替代 PSR-0
PSR-0 不一樣的是,取消掉了 _ 做爲分隔符和目錄結構。

composer 執行 install 等操做時,composer 會把文件中的配置存儲在 vendor/composer/autoload_psr4.php文件中的返回數組中。

例如:定義了Very\Good=>vendor\Lionis\IsReal\Cool,在調用 use Very\Good\
Love\SomeClass,PSR-4 加載的實際目錄爲 vendor/Lionis/IsReal/Cool/Love/SomeClass.php。

composer.json配置:

"autoload": {
    "psr-4": {
        "Very\\Good": "vendor\Lionis\IsReal\Cool"
    }
}

classmap

classmap 經過配置指定的目錄和文件,在 composer 執行 install 等操做時,composer 會去掃描對應的目錄下以.php結尾的文件中的 class,並存儲在 vendor/composer/autoload_classmap.php文件中的返回數組中。

composer.json配置:

"autoload": {
    "classmap": [
        "Lionis/",
        "Xiaoer/"
    ]
}

若是 Lionis 下有一個叫 VeryCool的文件,那麼在vendor/composer/autoload_classmap.php 中會生成。

<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'VeryCool' => $baseDir . '/Lionis/VeryCool.php',
    // 其餘的映射
);

files

files 就是直接簡單粗暴的加載文件。在 composer 執行 install 等操做時,composer 會把文件中的配置存儲在 vendor/composer/autoload_static.php文件中的生成一個 $files 數組。

composer.json 配置:

"autoload": {
    "files": ["Lionis/Very/Cool.php"]
}

小結

composer 經過使用 composer.json,用 json 的格式來指定咱們須要自動加載規則。咱們只要在入口文件引入 vendor/autoload.php 就能很方便的便能使用 自動加載

若是你對 composer 實現 自動加載 的原理感興趣,能夠順着 vendor 中的 autoload.php 去看看源碼。

總結

石器時代信息時代PHP 經歷了不少試驗和改變後正在變得愈來愈好。固然,許多優秀的框架讓咱們開發速度更快,須要理解的一些知識點也隨之被隱藏起來,讓咱們更加專一於實現邏輯。可是,咱們有的時候仍是要嘗試的去理解他們工做的原理,來提高咱們本身。像我老師說過的,所不定一會兒踩到狗屎運了呢。

更多

細說 PHP 類庫自動加載

一塊兒成長

在困惑的城市裏總少不了並肩同行的 夥伴 讓咱們一塊兒成長。
  • 若是您想讓更多人看到文章能夠點個 點贊
  • 若是您想激勵小二能夠到 Github 給個 小星星
  • 若是您想與小二更多交流添加微信 m353839115

微信公衆號

本文原稿來自 PushMeTop
相關文章
相關標籤/搜索