首頁  >  文章  >  後端開發  >  你所不知道的 PHP - 自動載入

你所不知道的 PHP - 自動載入

高洛峰
高洛峰原創
2016-11-07 16:51:311451瀏覽

很多的朋友在,學習 PHP 的時候最早面對的問題之一就是 require 、 include 和 require_once 、include_once 的相愛相殺。

在了解了它們相愛相殺的故事後,往往就開始使用起了框架。框架固然是工作的好工具,但你知道你平常 new 一個新類別的時候,發生了什麼事嗎?有想過為什麼我們 遵循規範 就會自動的幫我們做好一切的加載嗎? 讓我們一切來探索發現其中的奧秘。

時間軸

蒸汽時代

在 PHP 代碼的頂部你是不是經常看到這樣的代碼。

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

如果只是引入幾個 PHP 腳本,那還可以接受。那引入成千上萬個腳本的時候,爆炸是在所難免的。如果對一個腳本改了個名字,還需要對引入改腳本的每個腳本改名,能不爆炸嗎?連打出這段話都怎麼繞。

電氣時代

在 PHP 電氣時代,開始出現了 __autoload 和 spl_autoload_register 函數註冊自訂的自動載入策略。

通俗的來說,__autoload 和 spl_autoload_register 是一個 殺手組織,他們會去僱用 各國殺手 (函數)。當我們想搞定某個人的時候(new),只需要提供名字(類名),剩下的 殺手 會幫我們搞定的。

__autoload

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

<?php// Lionis.phpclass Lionis {  
  public function __construct() {    
      echo &#39;欧耶耶, 我就是 Lionis&#39;;
    }
}
<?php
// index.php
function __autoload($classname) {
    $filename = &#39;./&#39; . $classname . &#39;.php&#39;;
    require_once $filename;
}

$lionis = new Lionis();

輸出

欧耶耶, 我就是 Lionis

spl_autoload_register

如果我們 項目 很大很老又或者你是一個 愛折騰 的少先隊員,需要的東西有不一樣的規範,這時候如果都放在這個函數馬上就會膨脹的。而且 __autoload 是全域唯一的,如果被佔用了,可能會導致錯誤。 (欲使一個人滅亡,必將先使其膨脹。)

PHP 5.1.2 開始提供此函數 傳送門,註冊給定的函數作為 __autoload 的實現。所以,我們來看一些框架或外掛程式在自己使用的時候,為了相容可能會出現 function_exists(spl_autoload_register)。

<?php
function lionisIsCoolFind($classname) {
    require &#39;./&#39; . $classname . &#39;.php&#39;;
}

// 函数
spl_autoload_register(&#39;lionisIsCoolFind&#39;);

// 匿名函数
spl_autoload_register(function($require) {
    require &#39;./&#39; . $classname . &#39;.php&#39;;
});

// 类中的函数
spl_autoload_register(array(&#39;Lionis&#39;, &#39;loadClass&#39;));

歐耶,這下我們可以寫很多不同的自動載入函數了。

資訊時代

師傅小心,前面有妖氣! 。如果我們每個人都自己實作一套自動載入的方法,每個PHP 元件和 框架都使用獨特的自動載入器,而且每個框架使用不同的邏輯來載入PHP類別、介面和性狀。

那當我們使用一些第三方框架的時候,還需要去弄清楚引導文件中的 自動載入器,那樣是有多和 時間 過不去呢。 PHP-FIG 體認到了這個問題了,建議使用 PSR-4 規範,以促進元件之間的 互通性,這樣我們就可以使用一個自動載入器了。

PSR-4 规范

利用命名空间的前缀和文件系统中的目录对应起来。

映射关系为

namespace    => filePath
\Lionis\Cool => cool

带有命名空间的类

<?php // 该文件为 
cool/Real.phpnamespace \
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(
    &#39;VeryCool&#39; => $baseDir . &#39;/Lionis/VeryCool.php&#39;,
    // 其他的映射
);

files

files 就是直接简单粗暴的加载文件。在 composer 执行 install 等操作时,composer 会把文件中的配置存储在vendor/composer/autoload_static.php文件中的生成一个 $files 数组。

composer.json 配置:

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


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn