[TOC]
* * * * *
## 1 文件加載的意義
大型項目工程中,通常將項目的功能組織**以文件進行組織**,并使用目錄進行劃分。
為了**使用不同文件中定義的函數,類等**,需要加載目標文件。
因此文件加載是**項目工程分文件組織**后,**加載功能目標文件**的方法。
## 2 文件的手動加載
>[info] 1 四個手動加載語言結構
* * * * *
**inculde**與**require**是php用來手動加載文件的函數,
**include_once**與**require_once**是限定同一個文件只被加載一次
1 首先按照參數給出的路徑查找
2 沒有給出目錄,從include_path指定目錄查找
3 include_path指定目錄查找失敗,在調用腳本文件所在目錄和當前工作目錄下查找
4 最后加載失敗時,include發出一條警告,而require會發出致命錯誤
這四個是**語言構造器或者說是語言結構**,通常后面**接一個字符串**。
與普通函數不同,普通函數后面接帶參數的大括號。
>[info] 2 示例
* * * * *
exampe1:基本的include例子。
~~~
vars.php
<?php
$color = 'green' ;
$fruit = 'apple' ;
?>
test.php
<?php
echo "A $color $fruit " ;
// A
include 'vars.php' ;
echo "A $color $fruit " ;
// A green apple
?>
~~~
>[danger] include等加載調用出現在一個函數里,則加載文件包含的代碼中的普通變量的作用域范圍就是該函數,其中的魔術變量是全局范圍。
example2:函數中include文件
~~~
<?php
function foo ()
{
global $color ;
include 'vars.php' ;
echo "A $color $fruit " ;
}
/*vars.php中的$furit的作用域在foo()函數中,因此
因此foo()函數正常輸出$fruit
echo語句中的$fruit為空
$color 聲明為全局變量 ,因此$color的作用域在全局。
foo() echo都輸出$color。
*/
foo ();
// A green apple
echo "A $color $fruit " ;
// A green
?>
~~~
>[info] 3 加載文件模式切換
加載文件時,php語法解析器會**從php模式切換到html模式**,**加載完文件后恢復到php模式**。因此也可以用來加載html文件,**其中的php代碼必須包含在php的起始與結束標記中**
>[info] 4 url加載遠程文件
php.ini的配置中URL fopen_wrappers激活時,可以使用url加載網絡服務器文件進行解釋。**與加載本地文件不同的是模板文件如果作為php代碼解釋,已經在服務器運行了,本地腳本只是包含其輸出結果**。通常使用其他的文件打開函數如readfile()等更好
example #3 通過 HTTP 進行的 include
~~~
<?php
include 'http://www.example.com/file.txt?foo=1&bar=2' ;
//txt文件不會被運行
include 'file.php?foo=1&bar=2' ;
//查找本地file.php?foo=1&bar=2文件,而不是運行file.php
include 'http://www.example.com/file.php?foo=1&bar=2' ;
// 查找遠程服務器的file.php,并以foo=1&bar=2參數運行。
$foo = 1 ;
$bar = 2 ;
include 'file.txt' ;
//加載本地file.txt文件
include 'file.php' ;
//加載本地file.php文件
?>
~~~
>[info] 5 加載返回值檢測
include等加載失敗時返回false,并發出警告,成功則返回1,除非包含文件使用return等給出了返回值。
需要注意的是include 不是函數,其參數不需要括號
example #4 比較 include 的返回值
~~~
<?php
//錯誤的檢查返回值格式,
if (include( 'vars.php' ) == 'OK' ) {
echo 'OK' ;
}
//正確的檢查其返回值格式
if ((include 'vars.php' ) == 'OK' ) {
echo 'OK' ;
}
?>
~~~
可以在目標文件中**使用return語句可以終止文件的加載,并返回調用的腳本**。thinkphp的默認**數組配置就是使用這個功能返回一個數組**。
example #5 include 和 return 語句
~~~
return.php
<?php
$var = 'PHP' ;
return $var ;
?>
noreturn.php
<?php
$var = 'PHP' ;
?>
testreturns.php
<?php
$foo = include 'return.php' ;
echo $foo ; // prints 'PHP'
$bar = include 'noreturn.php' ;
echo $bar ; // prints 1
?>
~~~
>[info] 6 加載包含函數的文件
包含文件中定義了函數,不管是return之前還是之后定義的,都可以獨立在主文件中使用。
**php5會對重復加載文件時出現的函數重復定義發出致命錯誤報告**。php4不會對return之后定義的函數報錯。**推薦使用include_once加載此類文件**
>[info] 7 tp5.0中手動加載的使用
~~~
index.php:
require __DIR__ . '/../thinkphp/start.php';
~~~
~~~
start.php:
require __DIR__ . '/base.php';
require CORE_PATH . 'Loader.php';
~~~
~~~
App.php
public static function run(){
...
if (!empty($config['extra_file_list'])) {
foreach ($config['extra_file_list'] as $file) {
$file = strpos($file, '.') ? $file : APP_PATH . $file . EXT;
if (is_file($file)) {
include_once $file;
}
}
}
...
}
private static function initModule($module, $config){
$module = (COMMON_MODULE == $module || !APP_MULTI_MODULE) ? '' : $module . DS;
if (is_file(APP_PATH . $module . 'init' . EXT)) {
include APP_PATH . $module . 'init' . EXT;
} else {
$path = APP_PATH . $module;
$config = Config::load(APP_PATH . $module . 'config' . EXT);
if ($config['app_status']) {
$config = Config::load(APP_PATH . $module . $config['app_status'] . EXT);
}
if ($config['extra_config_list']) {
foreach ($config['extra_config_list'] as $name => $file) {
$file = strpos($file, '.') ? $file : $path . $file . EXT;
Config::load($file, is_string($name) ? $name : pathinfo($file, PATHINFO_FILENAME));
}
}
if (is_file($path . 'alias' . EXT)) {
Loader::addMap(include $path . 'alias' . EXT);
}
if (APP_HOOK && is_file($path . 'tags' . EXT)) {
Hook::import(include $path . 'tags' . EXT);
}
if (is_file($path . 'common' . EXT)) {
include $path . 'common' . EXT;
}
if ($config['lang_switch_on'] && $module) {
Lang::load($path . 'lang' . DS . LANG_SET . EXT);
}
}
}
~~~
## 3 文件的自動加載
在php引入面向對象編程思想后,
開發者習慣將每個類的定義建立一個php文件。
使用這些類需要使用require加載需要的類文件。
為了簡化類的加載,php中引入了類的自動加載
>[info] 1 __autoload
在php5中可以通過定義一個__auload()函數,
使用未被定義的類時自動調用。
通過調用此函數,腳本引擎可以加載目標類文件
~~~
<?php
function __autoload ( $class_name ) {
require_once $class_name . '.php' ;
}
$obj = new MyClass1 ();
$obj2 = new MyClass2 ();
//在上面創建對象時,會調用__autoload,使用require加載對應的Myclass1.php類文件和MyClass2.php類文件。
?>
~~~
加載的異常處理
~~~
<?php
function __autoload ( $name ) {
echo "Want to load $name .\n" ;
throw new Exception ( "Unable to load $name ." );
}
try {
$obj = new NonLoadableClass ();
} catch ( Exception $e ) {
echo $e -> getMessage (), "\n" ;
}
?>
~~~
輸出:
Want to load NonLoadableClass.
Unable to load NonLoadableClass.
提示類加載失敗
5.3+版本后,__autoload 函數拋出的異常,可以被 catch 語句塊捕獲。
拋出的是一個自定義異常,那么必須存在相應的自定義異常類
__autoload 函數可以遞歸的自動加載自定義異常類。
~~~
<?php
function __autoload ( $name ) {
echo "Want to load $name .\n" ;
throw new MissingException ( "Unable to load $name ." );
}
try {
$obj = new NonLoadableClass ();
} catch ( Exception $e ) {
echo $e -> getMessage (), "\n" ;
}
?>
~~~
輸出:
Want to load NonLoadableClass.
Want to load MissingException.Fatal error: Class 'MissingException' not found in testMissingException.php on line 4
異常類查找失敗
>[info] 2 spl_autoload
SPL提供了一個__autoload()函數默認實現。
如果不使用任何參數調用 autoload_register() 函數,則以后在進行 __autoload() 調用時會自動使用此函數
`void spl_autoload ( string $class_name [, string $file_extensions ] )`
> $class_name 加載的類名
> $file_extensions 文件后綴,默認為.inc或.php
* * * * *
>[info] 3 spl_autoload_register
注冊給定的函數作為 __autoload 的實現,并將函數注冊到SPL __autoload函數隊列中
該函數會將__autoload()函數取代為lspl_autoload()或者spl_autoload_call()
因此程序中實現的__autoload()函數,需要使用該函數注冊到SPL __autoload隊列中
需要多條autoload函數,使用該函數。
實際上創建了autoload函數隊列,按照定義逐個執行
而__autoload()只可定義一個
`bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )`
> $autoload_function 自動加載函數,省略則為spl_autoload
> $throw 注冊失敗時,是否拋出異常
> $prepend 添加到加載函數隊列隊首,還是加載函數隊尾
spl_autoload_register()示例
~~~
<?php
// function __autoload($class) {
// include 'classes/' . $class . '.class.php';
// }
function my_autoloader ( $class ) {
include 'classes/' . $class . '.class.php' ;
}
spl_autoload_register ( 'my_autoloader' );
// 自 PHP 5.3.0 起可以使用一個匿名函數
spl_autoload_register (function ( $class ) {
include 'classes/' . $class . '.class.php' ;
});
?>
~~~
spl_autoload_register()加載失敗示例
~~~
<?php
namespace Foobar ;
class Foo {
static public function test ( $name ) {
print '[[' . $name . ']]' ;
}
}
spl_autoload_register ( __NAMESPACE__ . '\Foo::test' );
new InexistentClass ;
?>
~~~
輸出:
[[Foobar\InexistentClass]]
Fatal error: Class 'Foobar\InexistentClass' not found in ...
>[info] 4 其他相關函數
spl_autoload_unregister() 注銷已注冊的__autoload()函數
spl_autoload_extensions() 修改spl_autoload()函數默認文件擴展名
spl_autoload_functions() 返回注冊的__autoload()函數
spl_autoload_call() 手動調用已注冊的__autoload()函數
* * * * *
**在php的面向對象編程中,通常使用spl_autoload_register()來進行類的自動加載**
* * * * *
## 4 composer的自動加載實現
使用composer安裝tp5后
thinkphp\vendor\composer\目錄中包含了composer的自動加載實現,
其目錄結構如下:

autoload_classmap.php ;類名映射文件
autoload_files.php ;文件名映射文件
autoload_namespace.php ;命名空間映射文件
autoload_psr4.php ;psr4規范修正文件
autoload_real.php ;composer加載器入口
ClassLoader.php ;composer加載器核心
>[info] 1 autoload_real.php
~~~
class ComposerAutoloaderInit900f8cefe6f24fb76e69c5c37058d680
{
// 全局唯一加載器實例,
private static $loader;
// 加載ClassLoader.php文件中的Composer\Autoload'ClassLoader類
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
// 生成加載器
public static function getLoader()
{
// 單例模式生成全局唯一加載器
if (null !== self::$loader) {
return self::$loader;
}
// 注冊加載器 檢測自動加載器的存在
spl_autoload_register(array('ComposerAutoloaderInit900f8cefe6f24fb76e69c5c37058d680', 'loadClassLoader'), true, true);
// 生成加載器實例
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
// 注銷自動加載器 對應上面的檢查過程,下面會再次注冊
spl_autoload_unregister(array('ComposerAutoloaderInit900f8cefe6f24fb76e69c5c37058d680', 'loadClassLoader'));
// 加載 命名空間映射文件。分析見下
$map = require __DIR__ . '/autoload_namespaces.php';
// 調用$loader->set() 設置命名空間別名路徑
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
// 加載 psr4規范修正文件
$map = require __DIR__ . '/autoload_psr4.php';
// 調用$laoder->setPsr4()設置命名空間別名路徑
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
// 加載 類映射文件
$classMap = require __DIR__ . '/autoload_classmap.php';
// 調用$loader->addClassMap() 設置類的別名
if ($classMap) {
$loader->addClassMap($classMap);
}
// 注冊加載器。
$loader->register(true);
// 加載 需要包含的文件
$includeFiles = require __DIR__ . '/autoload_files.php';
// 調用下面的函數依次加載需要包含的文件
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire900f8cefe6f24fb76e69c5c37058d680($fileIdentifier, $file);
}
return $loader;
}
}
// 加載目標文件,并保存加載信息到全局變量
$GLOBALS['_composer_autolod_files'],防止重復加載
function composerRequire900f8cefe6f24fb76e69c5c37058d680($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
~~~
>[info] 2 ClassLoader.php composer自動加載器核心
* * * * *
>[info] 成員變量
~~~
PSR-4規范
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
PSR-0規范
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
~~~
* * * * *
>[info] 成員方法
PSR-0
> getPrefixes() 獲取前綴設置
`public function getPrefixes()`
> getFallbackDirs() 獲取搜索目錄
`public function getFallbackDirs()`
> add() 添加搜索目錄
`public function add($prefix, $paths, $prepend = false)`
> setPsr4() 修改搜索目錄前綴索引
`public function set($prefix, $paths)`
PSR-4
> getPrefixesPsr4() 獲取前綴設置
` public function getPrefixesPsr4()`
> getFallbackDirsPsr4() 獲取搜索目錄
`public function getFallbackDirsPsr4()`
> addPsr4() 添加搜索目錄
`public function addPsr4($prefix, $paths, $prepend = false)`
> setPsr4() 修改搜索目錄前綴索引
`public function setPsr4($prefix, $paths)`
其他
> getClassMap() 獲取類名映射信息
`public function getClassMap()`
> addClassMap() 添加類名映射信息
`public function addClassMap(array $classMap)`
> setUseIncludePath() 設置是否搜索include_path
`public function setUseIncludePath($useIncludePath)`
> getUseInlcudePath() 獲取是否搜索include_path
public function getUseIncludePath()
> register() 注冊加載函數
`public function register($prepend = false)`
> unregister() 注銷加載函數
public function unregister()
> loadClsss() 加載目標類
`public function loadClass($class)`
> findFile() 搜索類目標文件
`public function findFile($class)`
> findFileWithExtension() 指定擴展名搜索文件
`private function findFileWithExtension($class, $ext)`
>[info] 3 其他文件
autoload_classmap.php
autoload_files.php
autoload_namespaces.php
autolaod_psr4.php
以**數組形式**返回需要操作的**映射信息**。
## 5 tp5的自動加載實現
thinkphp5的自動加載實現在Loader.php文件
分析見 [附:(Loader.php)自動加載](http://www.hmoore.net/zmwtp/tp5/119431)
- 更新記錄
- 概述
- 文件索引
- 函數索引
- 章節格式
- 框架流程
- 前:章節說明
- 主:(index.php)入口
- 主:(start.php)框架引導
- 主:(App.php)應用啟動
- 主:(App.php)應用調度
- C:(Controller.php)應用控制器
- M:(Model.php)數據模型
- V:(View.php)視圖對象
- 附:(App.php)應用啟動
- 附:(base.php)全局變量
- 附:(common.php)模式配置
- 附:(convention.php)全局配置
- 附:(Loader.php)自動加載器
- 附:(Build.php)自動生成
- 附:(Hook.php)監聽回調
- 附:(Route.php)全局路由
- 附:(Response.php)數據輸出
- 附:(Log.php)日志記錄
- 附:(Exception.php)異常處理
- 框架工具
- 另:(helper.php)輔助函數
- 另:(Cache.php)數據緩存
- 另:(Cookie.php)cookie操作
- 另:(Console.php)控制臺
- 另:(Debug.php)開發調試
- 另:(Error.php)錯誤處理
- 另:(Url.php)Url操作文件
- 另:(Loader.php)加載器實例化
- 另:(Input.php)數據輸入
- 另:(Lang.php)語言包管理
- 另:(ORM.php)ORM基類
- 另:(Process.php)進程管理
- 另:(Session.php)session操作
- 另:(Template.php)模板解析
- 框架驅動
- D:(\config)配置解析
- D:(\controller)控制器擴展
- D:(\model)模型擴展
- D:(\db)數據庫驅動
- D:(\view)模板解析
- D:(\template)模板標簽庫
- D:(\session)session驅動
- D:(\cache)緩存驅動
- D:(\console)控制臺
- D:(\process)進程擴展
- T:(\traits)Trait目錄
- D:(\exception)異常實現
- D:(\log)日志驅動
- 使用范例
- 服務器與框架的安裝
- 控制器操作
- 數據模型操作
- 視圖渲染控制
- MVC開發初探
- 模塊開發
- 入口文件定義全局變量
- 運行模式開發
- 框架配置
- 自動生成應用
- 事件與插件注冊
- 路由規則注冊
- 輸出控制
- 多種應用組織
- 綜合應用
- tp框架整合后臺auto架構快速開發
- 基礎原理
- php默認全局變量
- php的魔術方法
- php命名空間
- php的自動加載
- php的composer
- php的反射
- php的trait機制
- php設計模式
- php的系統時區
- php的異常錯誤
- php的輸出控制
- php的正則表達式
- php的閉包函數
- php的會話控制
- php的接口
- php的PDO
- php的字符串操作
- php的curl
- 框架心得
- 心:整體結構
- 心:配置詳解
- 心:加載器詳解
- 心:輸入輸出詳解
- 心:url路由詳解
- 心:模板詳解
- 心:模型詳解
- 心:日志詳解
- 心:緩存詳解
- 心:控制臺詳解
- 框架更新
- 4.20(驗證類,助手函數)
- 4.27(新模型Model功能)
- 5.4(新數據庫驅動)
- 7.28(自動加載)