@Chiang
2020-05-02T17:05:54.000000Z
字数 5683
阅读 849
Composer
2020-05
在 PHP 开发过程中,如果希望从外部引入一个 class,通常会使用 include 和 require 方法,去把定义这个 class 的文件包含进来。这个在小规模开发的时候,没什么大问题。但在大型的开发项目中,使用这种方式会带来一些隐含的问题:如果一个 PHP 文件需要使用很多其它类,那么就需要很多的 require/include 语句,这样有可能会造成遗漏或者包含进不必要的类文件。如果大量的文件都需要使用其它的类,那么要保证每个文件都包含正确的类文件肯定是一个噩梦, 况且 require_once 的代价很大。
PHP5 为这个问题提供了一个解决方案,这就是类的自动装载 (autoload) 机制。 autoload 机制可以使得 PHP 程序有可能在使用类时才自动包含类文件,而不是一开始就将所有的类文件 include 进来,这种机制也称为 lazy loading。
总结起来,自动加载功能带来了几处优点:
- 用类之前无需 include 或者 require。
- 使用类的时候才会 require/include 文件,实现了 lazy loading,避免了 require/include 多余文件。
- 无需考虑引入类的实际磁盘地址,实现了逻辑和实体文件的分离。
使用
PHP
的自动加载函数__autoload()
和SPL Autoload
(Standard PHP Library) 还有Namespace
命名空间 实现类名与实际的磁盘文件映射,实现了逻辑和实体文件的分离,这样编码的逻辑更加灵活.实现的必要条件有了,实现规则有很多,我们还需要PSR 标准来统一编码规范.
可以通过
composer init
命令行创建,也可以自定义
eg.
这里展示
laravel
的composer
{
"name": "laravel/laravel",
"type": "project",
"description": "The Laravel Framework.",
"keywords": [
"framework",
"laravel"
],
"license": "MIT",
"require": {
"php": "^7.2",
"fideloper/proxy": "^4.0",
"laravel/framework": "^6.2",
"laravel/tinker": "^2.0"
},
"require-dev": {
"facade/ignition": "^1.4",
"fzaninotto/faker": "^1.4",
"mockery/mockery": "^1.0",
"nunomaduro/collision": "^3.0",
"phpunit/phpunit": "^8.0"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"laravel": {
"dont-discover": []
}
},
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
]
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
]
}
}
- 参考
laravel
的 文件- 这里的说明很清楚了
- 具体也可以查看链接,解释了是否要把
composer.lock
放入git repo中
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
...
}
- What's the difference between composer.lock and installed.json?
composer.lock
is generated when installing for the first time or updating. It contains references to the exact versions used. It should be committed into the version tracking repository to allow restoring this exact combination of libraries.installed.json
is an internal file of Composer. It's used when you remove a package manually fromcomposer.json
to remove the files from the vendor directory. Otherwise, the old vendor package would be around forever.
//创建 composer.json 文件
composer init
//安装项目
composer install
.
├── composer.json // composer init 生成的配置文件
└── vendor
├── autoload.php // composer 入口文件
└── composer
├── ClassLoader.php // composer 核心类文件
├── LICENSE
├── autoload_classmap.php // 类名与磁盘路径直接匹配映射
├── autoload_namespaces.php // 为需要加载的命名空间前缀定义路径
├── autoload_psr4.php // 根据 Psr4 规范定义命名空间前缀和路径
├── autoload_real.php // composer 加载配置逻辑
├── autoload_static.php // 包含所有需要加载的文件、类,内容包含以上文件
├── autoload_files.php // 定义所有需要加载的配置文件
└── installed.json // 参看上文解释
autoload_real.php
:自动加载功能的引导类。任务是 composer 加载类的初始化 (顶级命名空间与文件路 径映射初始化) 和注册 (spl_autoload_register ()
)。- ClassLoader.php:composer 加载类。composer 自动加载功能的核心类。
autoload_static.php:顶级命名空间初始化类,用于给核心类初始化顶级命名空间。- autoload_classmap.php:自动加载的最简单形式,有完整的命名空间和文件目录的映射;
- autoload_files.php:用于加载全局函数的文件,存放各个全局函数所在的文件路径名;
- autoload_namespaces.php:符合 PSR0 标准的自动加载文件,存放着顶级命名空间与文件的映射;
- autoload_psr4.php:符合 PSR4 标准的自动加载文件,存放着顶级命名空间与文件的映射;
这些文件是随着项目全局加载的
{
"autoload": {
"files": [
"src/Illuminate/Foundation/helpers.php",
"src/Illuminate/Support/helpers.php"
],
"psr-4": {
"Illuminate\\": "src/Illuminate/"
}
},
"autoload-dev": {
"files": [
"tests/Database/stubs/MigrationCreatorFakeMigration.php"
],
"psr-4": {
"Illuminate\\Tests\\": "tests/"
}
}
}
这里我们通过
laravel
项目的composer来解释,上面下载的composer
包没有自定义文件的引入代码
- autoload_real.php 文件多了一些代码
public static function getLoader()
{
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit5620d294729feab5b1620b129a756f81::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire5620d294729feab5b1620b129a756f81($fileIdentifier, $file);
}
}
function composerRequire5620d294729feab5b1620b129a756f81($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
- composer 文件夹下多了
autoload_files.php
文件
在这里我们把函数放在app/Support/Helpers/CustomHelper.php内:
<?php
if (! function_exists('test_function')) {
function test_function() {
echo "我是一个自定义辅助函数";
}
}
创建文件app/Support/Helpers/Helpers.php,并载入包含有自定义函数的文件:
<?php
$helpers = [
'CustomHelper.php'
];
// 载入
foreach ($helpers as $helperFileName) {
include __DIR__ . '/' .$helperFileName;
}
/*composer.json*/
{
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
},
"files": [
"app/Support/Helpers/helpers.php"
]
}
}
运行如下命令:
composerdump-autoload
运行后就可以在任意地方调用你的自定义函数了
参考资料:
composer 自动加载
Composer 自动加载原理
由浅入深的了解一下composer自动加载机制
Composer自动加载源码解析
PHP 自动加载功能原理解析
Composer 的 Autoload 源码实现——启动与初始化
Composer 的 Autoload 源码实现——注册与运行
PHP中PSR-[0-4]规范
composer.json 架构
Composer.json配置文件说明
为Laravel 5 添加自定义辅助函数
深入解析 composer 的自动加载原理
为什么Composer在生产环境要使用dumpautoload
What's the difference between composer.lock and installed.json?