composer的自动加载机制(autoload)
composer的出现真是让人们眼前一亮,web开发从此变成了一件很『好玩』的事情,开发一个CMS就像在搭积木,从packagist中取出『积木』搭建在自己的代码中,一点一点搭建出一个属于自己的王国。
从此以后我基本就抛弃了require和include函数,一个项目中,这两个函数只可能出现一次,那就是require '../vendor/autoload.php'。
那么,既然抛弃了传统的文件包含方法,我们使用所有类库都将用namespace和composer自带的autoload。可是,我们自己编写的函数库与类库,怎么用composer的方法来自动加载呢?
这就要从composer.json说起,我们需要通过修改这个文件来达到目的。
composer.json相当于是composer的配置文件,这个配置文件中有一个autoload段,比如我的一个项目:

其中又包含主要的两个选项: files 和 psr-4。
files就是需要composer自动帮我们加载的函数库(不含类),只要在后面的数组中将函数库的文件路径写入即可。
psr-4顾名思义,是一个基于psr-4(http://www.php-fig.org/psr/psr-4/)规则的类库自动加载对应关系,只要在其后的对象中,以 "命名空间": "路径" 的方式写入自己的类库信息即可。
修改完成后,只要执行一下composer update,即可完成对应工作。
之后,我们在项目中,用如下方式即可加载自定义类库:
new \Mrgoon\AliSms\AliSms();
composer的autoload将会自动包含”./mrgoon/aliyun-sms/src/.AliSms.php”,并找到其中的Mrgoon\AliSms命名空间下的AliSms类。
我们来深挖一下,探索一下autoload的原理。
在我们修改完composer.json并执行update后,将会修改./vender/composer/autoload_psr4.php,比如我的某个项目,其中增加了这样一个对应关系:

这其实就是我刚刚在.json中添加的对应关系,他等于将.josn的配置文件,换成了php的形式。
那么我看到vendor/autoload.php:
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInitff1d77c91141523097b07ee2acc23326::getLoader();
其执行了一个自动生成的类ComposerAutoloaderInitff1d77c91141523097b07ee2acc23326中的getLoader方法。
跟进:
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitff1d77c91141523097b07ee2acc23326', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitff1d77c91141523097b07ee2acc23326', 'loadClassLoader'));
$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);
}
$loader->register(true);
$includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $file) {
composerRequireff1d77c91141523097b07ee2acc23326($file);
}
return $loader;
}
可以明显看到,他将autoload_namespaces.php、autoload_psr4.php、autoload_classmap.php、autoload_files.php等几个配置文件包含了进来,并进行了相关处理(setPsr4),最后注册(register)。
那么我们跟进register方法:
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
这函数就一行,但简单明了,直接调用php自带的spl_autoload_register函数,注册处理__autoload的方法,也就是loadClass方法。再跟进loadClass方法:
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
从函数名字就可以大概知道流程:如果存在$class对应的这个$file,则include进来。
那么进findFile方法里看看吧:
public function findFile($class)
{
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
return false;
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if ($file === null) {
// Remember that this class does not exist.
return $this->classMap[$class] = false;
}
return $file;
}
通过类名找文件,最终锁定在findFileWithExtension方法中。
不过发现了一个小宝藏:在php5.3.0~5.3.2版本下,类名的第一个字符是\的小bug,也许以后挖漏洞会用上。
还是跟进findFileWithExtension方法:
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
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;
}
}
最终实现将命名空间\类这样的类名,给转换成目录名/类名.php这样的路径,并返回完整路径。
我发现composer的autoload与php自带的spl_autoload,在包含文件时有一点小区别。那就是,spl_autoload会查找.inc类型的文件名,但composer不会。
另外也可以发现,虽然配置文件的名字是autoload_psr4.php,但实际上psr0格式的自动加载也是支持的。二者最大的不同就是psr0中用”_”来代替目录间的”\”。
composer的自动加载机制(autoload)的更多相关文章
- Composer 的自动加载机制
Composer 的自动加载机制 Composer 提供了四种自动加载方式,分别是 PSR-0.PSR-4.生成 classmap 以及之间包含 files. PSR-0 方式 PSR-0 方式要求目 ...
- 详解composer的自动加载机制
composer是一个用PHP开发的用来管理项目依赖的工具,当你在项目中声明了依赖关系后,composer可以自动帮你下载和安装这些依赖库,并实现自动加载代码. 安装composer composer ...
- CI框架源码阅读笔记9 CI的自动加载机制autoload
本篇并不是对某一组件的详细源码分析,而只是简单的跟踪了下CI的autoload的基本流程.因此,可以看做是Loader组件的分析前篇. CI框架中,允许你配置autoload数组,这样,在你的应用程序 ...
- Yii2的深入学习--自动加载机制
Yii2 的自动加载分两部分,一部分是 Composer 的自动加载机制,另一部分是 Yii2 框架自身的自动加载机制. Composer自动加载 对于库的自动加载信息,Composer 生成了一个 ...
- Yii2的深入学习--自动加载机制(转)
Yii2 的自动加载分两部分,一部分是 Composer 的自动加载机制,另一部分是 Yii2 框架自身的自动加载机制. Composer自动加载 对于库的自动加载信息,Composer 生成了一个 ...
- composer 实现自动加载原理
简介 一般在框架中都会用到composer工具,用它来管理依赖.其中composer有类的自动加载机制,可以加载composer下载的库中的所有的类文件.那么composer的自动加载机制是怎么实现的 ...
- 说说PHP的autoLoad自动加载机制
__autoload的使用方法1: 最经常使用的就是这种方法,根据类名,找出类文件,然后require_one 复制代码 代码如下:function __autoload($class_name) { ...
- PHP autoload与spl_autoload自动加载机制的深入理解
PHP autoload与spl_autoload自动加载机制的深入理解 作者: 字体:[增加 减小] 类型:转载 时间:2013-06-05我要评论 本篇文章是对PHP中的autoload与spl_ ...
- 深入解析 composer 的自动加载原理 (转)
深入解析 composer 的自动加载原理 转自:https://segmentfault.com/a/1190000014948542 前言 PHP 自5.3的版本之后,已经重焕新生,命名空间.性状 ...
随机推荐
- Java多态性应用——多态数组、多态参数
多态数组: Person[] person = {new Person("张三", 32), new Student("李四", 21, 120, 90.0), ...
- Java中 Json的使用
转自:http://huyan.couplecoders.tech/%E5%BC%80%E5%8F%91%E8%80%85%E6%89%8B%E5%86%8C/2018/11/02/Java%E4%B ...
- QToolButton设置icon的大小
项目中用到了QToolButton上使用图片. 如果在maindow中直接使用QToolButton,如: btnSimulate = new QToolButton; btnSimulate-> ...
- osi七层协议 Open System Interconnection
一, 操作系统基础 操作系统:(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在"裸机"上的最基本的系统软件,任何其他软件都必 ...
- 在eclipse上配置多个jdk
在实际生产中,可能会遇到这样的问题:在eclipse中存在多个项目时,可能不同的项目需要不同的jdk版本.这时,我们就可以给eclipse配置多个jdk进行切换. 注:貌似只有较新版eclipse才能 ...
- SCUT - 297 - 狂符「幻视调律(Visionary Tuning)」 - 重链剖分
https://scut.online/p/297 一般的树剖是关于点权的,但是突发奇想好像边权也是一样的.做一些小改动. #include<bits/stdc++.h> #define ...
- 25.conda 下载安装与运用
转载:https://www.cnblogs.com/gandoufu/p/9748841.html https://blog.csdn.net/tuzixini/article/details/81 ...
- python学习笔记(12):高级面向对象
一.__slots__和property 1.__slots__魔术函数动态的添加方法和属性 2.直接暴露属性的局限性 3.使用get/set方法 4.利用@property简化get/set方法 5 ...
- 01.Windows2008R2系统禁启SMBv1服务命令
微软漏洞安全问题: 检测:默认配置 = 已启用(未创建注册表项),所以不会返回 SMB1 值.Get-Item HKLM:\SYSTEM\CurrentControlSet\Services\Lanm ...
- Redis安装配置以及开机启动
1.下载源码,解压缩后编译源码. $ wget http://download.redis.io/releases/redis-2.8.3.tar.gz $ .tar.gz $ cd redis- ...