# composer機制
> *Composer*?是 PHP 中用來管理依賴(dependency)關系的工具,它可以幫我們自動加載類文件(前提是定義好命名空間和目錄的映射關系),并且是惰性加載,在使用類時才自動加載,而不是一開始就加載全部類文件
## 1. 魔術方法__autoload
當類不存在時,自動加載類文件(前提是自己需要自己定義好類和類文件的映射規則)
### 1.1 為什么不用__autoload
*__autoload*是全局函數,只能定義一次,所有類和類文件映射規則只能在*\_\_autoload*函數定義,會造成*\_\_autoload*臃腫
## 2. spl_autoload_register
*spl_authoload_register*是__autoload的調用堆棧,可以定義多個*spl_authoload_register*,不同的映射的規則定義到*spl_authoload_register*中
## 3. PSR-4
*PSR-4*規范了如何指定文件路徑從而自動加載類定義,同時規范了自動加載文件的位置
### 3.1 PSR-4和PSR-0的區別
*psr-4*和*psr-0*都可以自動加載類,兩者的區別如下:
#### 3.1.1 psr-0有更深的目錄
例如我們使用use church\testClass,composer.json定義如下
```json
# psr-0
{
"autoload": {
"psr-0": {
"church\\": "./src/"
}
}
}
# psr-4
{
"autoload": {
"psr-4": {
"church\\": "./src/"
}
}
}
```
- psr-0對應類文件為:./src/church/testClass.php
- psr-4對應類文件為:./src/testClass.php
#### 3.1.2 psr-4命名空間要求“/”結尾
```json
{
"autoload": {
"psr-4": {
"church\\": "./src/"
}
}
}
```
church命名空間必須以方斜杠\結尾,否則報錯如下:
```bash
[InvalidArgumentException]
A non-empty PSR-4 prefix must end with a namespace separator.
```
#### 3.1.3 psr-4下劃線無意義(沒搞懂)
psr-4下劃線無意義,而psr-0類名有下劃線,則會轉為斜杠/
## 4. composer機制
### 4.1 疑問
什么時候去解析composer.json文件,如何解析composer.json文件?
> 應該是在composer update,composer install時會根據composer.json定義的autoload屬性,自動保存映射關系到對應文件
### 4.2 源碼
#### 4.2.1 實例化核心加載類 Composer\Autoload\ClassLoader
#### 4.2.2 設置ClassLoader屬性
設置prefixLengthsPsr4, prefixDirsPsr4, prefixesPsr0,如下有兩種方式,一種是直接在autoload_static.php讀取,另一種是通過autoload_namespaces.php,autoload_psr4.php,autoload_classmap.php讀取
```php
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitc9aa9b19e38ff570843aae65d73b4f16::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
```
#### 4.2.3 注冊到spl_autoload_register調用堆棧
```php
$loader->register(true);
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
```
#### 4.2.4 類和文件映射規則
```php
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
```
大概過程如下:prefixLengthsPsr4 -> prefixDirsPsr4 -> fallbackDirsPsr4
### 4.3 使用
### 4.3.1 初始化composer
```bash
php composer.phar init
```
### 4.3.2 編輯composer.json,添加自己的命名空間和全局函數
```json
# composer.json中的autoload鍵
"autoload": {
"psr-4": {
"App\\": "app/"
},
"files": [
"app/Swoft.php",
"app/Helper/Functions.php"
],
"classmap": [
"src/"
]
},
```
- psr-4命名空間,保存在autoload_psr4.php文件中
- files全局函數,保存在autoload_files.php文件中
- classmap掃描src所有文件,以namespace+classname作為鍵,文件作為值,保存在autoload_classmap.php文件中
##### 注意:修改composer.json后,需要composer update
## 4.3.3 composer常用命令
```bash
# 安裝
php7 composer.phar require wuzhc/zcswoole -vvv
# 卸載
php7 composer.phar remove wuzhc/zcswoole -vvv
# 創建項目
composer create-project --prefer-dist yiisoft/yii2-app-advanced yii-application
```
### 參數說明
- `--prefer-dist` 會從github 上下載.zip壓縮包,并緩存到本地。下次再安裝就會從本地加載,大大加速安裝速度。但她沒有保留 .git文件夾,沒有版本信息。適合基于這個package進行開發。
- `--prefer-source` 會從github 上clone 源代碼,不會在本地緩存。但她保留了.git文件夾,從而可以實現版本控制。適合用于修改源代碼。
## 5. 參考
[深入解析 composer 的自動加載原理](https://segmentfault.com/a/1190000014948542#articleHeader10)
- php
- 編譯安裝
- 基本概念
- 垃圾回收機制
- 生命周期
- zval底層實現
- c擴展開發
- gdb調試工具
- 自定義擴展簡單demo
- 鉤子函數
- 讀取php.ini配置
- 數組
- 函數
- 類
- yaf擴展底層源碼
- swoole擴展底層源碼
- memoryGlobal內存池
- swoole協程使用記錄
- 單點登錄sso原理
- compser使用
- session實現機制
- c & linux
- gcc
- 指針
- 結構體,聯合和位字段
- 宏定義井號說明
- printf家族函數和可變參數
- 共享函數
- 靜態庫和動態庫
- makefile自動化構建
- 信號一
- 信號二
- inotify監控文件事件
- socket編程
- 簡介
- UNIX DOMAIN
- Internet DOMAIN
- TCP/IP
- 文件IO多路復用
- 內存管理
- 進程組,會話和控制終端
- daemon守護進程
- 多進程
- 多線程
- 常用進制轉換
- go
- 入門知識
- 字節和整數裝換
- python
- redis
- 應用場景
- 消息隊列
- 熱點數據
- 掃碼登錄
- 訂閱發布
- 次數限制
- 搶購超賣
- 持久化機制
- mysql
- 工作流程
- MyISAM和InnoDB區別
- 用戶和權限管理
- 執行計劃
- sql優化
- 事務和鎖
- 慢查詢日志
- case...when...then...end用法
- sql
- 參考
- linux
- 內核參數優化
- 防火墻設置
- docker
- docker入門知識
- 算法
- 多維數組合
- DFA算法
- 紅包金額分配