composer
composer是php的依赖管理工具,学习使用composer是学习php的一大助力。
为什么需要自动加载?
因为在大型php项目开发过程中,需要引入大量的php文件。如果所有文件都要手动引入的话会比较麻烦,且项目代码难以管理,所以使用composer自动加载php文件依赖。
php的自动加载函数
php
/**
* php 自动加载函数
* @param callable $callback;
* @Param bool $throw = true;
* @Param bool $prepend = false;
*/
spl_autoload_register(function (string $class) {
$file = $class . ".php";
if (!is_file($file)) {
throw new \Exception('file does not exists');
}
require $file;
});
//类写法
class Bind
{
//非静态函数
public function _autoload($class)
{
$file = $class . ".php";
if (!is_file($file)) {
throw new \Exception('file does not exists');
}
require $file;
}
}
spl_autoload_register([new Bind,'_autoload']);PSR标准:
PSR标准是php社区制定的自动加载标准,旨在规范文件的自动加载行为,确保代码的可移植性。PSR-4是推出的第5个规范,制定了文件路径从何自动加载类定义,同时规范了自动加载文件的位置。
composer如何实现自动加载
源文件认识
php文件的命名空间要符合PSR-4命名空间的规范。
先了解composer自动加载所用到的源文件的功能或作用。
- Autoload_real:自动加载功能的引导类。
- ClassLoader.php:
composer加载类, 自动加载功能的核心类 - Autoload_static.php:顶级命名空间初始化类,用于给核心类初始化顶级命名空间。
- Autoload_classmap.php:自动加载的简单形式,有完整的命名空间和文件路径映射。
- Autoload_files.php:用于加载全局函数的文件。存放各个全局函数所在的文件路径名。
- Autoload_namespace.php:符合
PSR-0标准的自动加载文件,存放着顶级命名空间与文件的映射。 - Autoload_psr4.php:符合PSR4的标准的自动加载文件,存放顶级命名空间与文件的映射。
目录结构
初始化composer工程:
php
composer init修改composer.json配置文件,添加自动加载配置项:
php
"autoload": {
"psr-4": {
"App\\": "App"
},
"files": [
"./helper.php"
]
},然后执行(每次修改配置文件之后都要执行):
php
composer install会自动生成vendor文件夹。
搭建一个只有composer的项目示例,不嵌入任何框架。项目文件示例:
php
.
├── App
│ └── Controller
│ ├── Bootstrap.php
│ └── Order.php
├── composer.json
├── composer.lock
├── helper.php
├── index.php
└── vendor
├── autoload.php
├── composer
│ ├── ClassLoader.php
│ ├── InstalledVersions.php
│ ├── LICENSE
│ ├── autoload_classmap.php
│ ├── autoload_files.php
│ ├── autoload_namespaces.php
│ ├── autoload_psr4.php
│ ├── autoload_real.php
│ ├── autoload_static.php
│ ├── installed.json
│ ├── installed.php
│ └── platform_check.php
├── monolog
│ └── monolog
│ ├── CHANGELOG.md
│ ├── ...入口文件:类似larval、TP等php框架,通过在入口文件添加以下代码启动composer的自动加载功能。
php
include './vendor/autoload.php';autoload.php文件代码如下:
php
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
//关键在这里,引入加载器
require_once __DIR__ . '/composer/autoload_real.php';
//并执行getLoader函数
return ComposerAutoloaderInit5b932d2402e1bb39b78eadbca7572089::getLoader();再看autoload_real.php文件:
php
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit5b932d2402e1bb39b78eadbca7572089
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
//单例模式,确保加载器只被初始化一次
if (null !== self::$loader) {
return self::$loader;
}
//开发环境检查,检查一些php版本啊啥的
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit5b932d2402e1bb39b78eadbca7572089', 'loadClassLoader'), true, true);
//初始化加载器给并赋值给$loader变量
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
//在 ClassLoader 初始化完成后,移除临时注册的 loadClassLoader 方法,因为它已经完成了它的任务(加载 ClassLoader 类)。
spl_autoload_unregister(array('ComposerAutoloaderInit5b932d2402e1bb39b78eadbca7572089', 'loadClassLoader'));
//引入autoload_static.php文件,里面定义了顶级命名空间的映射关系。
require __DIR__ . '/autoload_static.php';
//1. 先执行 autoload_static.php文件中定义的ComposerStaticInit5b932d2402e1bb39b78eadbca7572089类里面的getInitializer静态方法,该方法返回一个回调函数
//2.用call_user_fuc调用 此回调函数,将autoload_static.php文件内的三种命名空间映射数据挂载道加载器 $loader对象中
call_user_func(\Composer\Autoload\ComposerStaticInit5b932d2402e1bb39b78eadbca7572089::getInitializer($loader));
//注册自动加载核心对象
//这里才是自动加载的核心功能,上面只是初始化映射关系和顶级命名空间映射。
//这里会执行一个php的自动加载函数,当执行到不认识的命名空间时,会执行此自动加载函数,在自动加载函数的闭包函数中,先对命名空间进行解析(具体怎么解析可以看ClassLoader 里面的findFile函数),
//如果解析成功,返回文件路径,通过 include 关键字引入文件。至此完成composer的自动加载流程
$loader->register(true);
//这里是自动加载全局函数
$includeFiles = \Composer\Autoload\ComposerStaticInit5b932d2402e1bb39b78eadbca7572089::$files;
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire5b932d2402e1bb39b78eadbca7572089($fileIdentifier, $file);
}
return $loader;
}
}
/**
* @param string $fileIdentifier
* @param string $file
* @return void
*/
function composerRequire5b932d2402e1bb39b78eadbca7572089($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}