composer源码简单分析(一)
2024-09-07 19:39:13
composer分析(一)
本文内容
- 基于PSR-4规范的自动加载 请结合文档和下面的代码注释
- spl_autoload_register
- php闭包Closure简单用法(大体使用情景: 生成回调提供使用, 使用闭包绑定类中的成员属性和方法)
框架引入composer自动加载器
require __DIR__ . '/../vendor/autoload.php';
autoload.php文件内容
<?php // autoload.php @generated by Composer require_once __DIR__ . '/composer/autoload_real.php'; // 返回自动加载器 object(Composer\Autoload\ClassLoader)
return ComposerAutoloaderInit251f259405d38ea713d5c2b4f861292a::getLoader();
getLoader方法
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
// 单例
if (null !== self::$loader) {
return self::$loader;
} // spl_autoload_register方法第一个参数为用户自定义的自动加载器,为一个callable,接收的参数为要加载类名
// 如self::$loader = $loader = new \Composer\Autoload\ClassLoader(); 此脚本中并没有ClassLoader这个类,由于注册了自动加载器loadClassLoader回调,
// 此方法就会接收到Composer\Autoload\ClassLoader这个字符串 手动require到本文件中 // 第二个参数true表示注册加载器失败时抛出异常
// 第三个参数true表示 将此自动加载器放到自动加载队列的首部,laravel中还使用此函数进行了类别名注册
spl_autoload_register(array('ComposerAutoloaderInit251f259405d38ea713d5c2b4f861292a', 'loadClassLoader'), true, true);
// 给loader赋值
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
// 卸载注册的自动加载回调
spl_autoload_unregister(array('ComposerAutoloaderInit251f259405d38ea713d5c2b4f861292a', 'loadClassLoader')); // 正常情况使用高版本php 此值恒为true
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
// require此静态加载文件 包含了大量供PSR-4使用的映射关系 后面会讲解composer包下各文件的用处
require_once __DIR__ . '/autoload_static.php';
// 重点在此回调的调用!!!
// 调用返回的闭包 注册映射关系到loader中
call_user_func(\Composer\Autoload\ComposerStaticInit251f259405d38ea713d5c2b4f861292a::getInitializer($loader));
} else {
// 如果$useStaticLoader为false 调用loader的set方法 手动注册映射关系到loader中 供后续加载时直接查找require文件
$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中存在映射关系后 注册真正的自动加载器 loadClass方法
$loader->register(true); if ($useStaticLoader) {
// 找到composer要自动加载的全局函数文件
$includeFiles = Composer\Autoload\ComposerStaticInit251f259405d38ea713d5c2b4f861292a::$files;
} else {
// 依然是找到composer提供的全局函数 和上面的功能一致
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire251f259405d38ea713d5c2b4f861292a($fileIdentifier, $file);
} return $loader;
}
autoload_static.php
public static function getInitializer(ClassLoader $loader)
{
// Closure bind方法返回的是一个闭包
return \Closure::bind(function () use ($loader) {
// 绑定映射关系到loader中
$loader->prefixLengthsPsr4 = ComposerStaticInit251f259405d38ea713d5c2b4f861292a::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit251f259405d38ea713d5c2b4f861292a::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit251f259405d38ea713d5c2b4f861292a::$prefixesPsr0;
$loader->classMap = ComposerStaticInit251f259405d38ea713d5c2b4f861292a::$classMap; }, null, ClassLoader::class);
}
ClassLoader.php
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
} /**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
// 拿到文件绝对路径
includeFile($file); return true;
}
} /**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
// 加载文件
include $file;
} /**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
// classmap中保存的是类名和其绝对路径的映射关系
if (isset($this->classMap[$class])) {
// var_dump($class); // Illuminate\Foundation\Application
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix . $class, $hit);
if ($hit) {
return $file;
}
} // 类名和路径映射关系不存在的情况下走此方法
$file = $this->findFileWithExtension($class, '.php'); // Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
} if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix . $class, $file);
} if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
} return $file;
} private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
// 处理文件名
// Illuminate\Foundation\Application 假设路径映射中不存在此类名
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
// 拿到文件名的第一个字母 依然去找映射关系
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class; // Illuminate\Foundation\Application
// 通过此步骤拿到类名的所有层级的命名空间 Illuminate\Foundation
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos); // Illuminate\Foundation
$search = $subPath . '\\';
// prefixDirsPsr4顶级命名空间前缀
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;
}
} ... return false;
}
Closure使用简单示例
<?php
$a = function () {
echo '123';
var_dump($this);
};
// var_dump($a);
// $a(); 报错
$abc = function () {
$this->privateVar = 456;
echo $this->privateVar, PHP_EOL;
};
$cba = function () {
echo $this->privateVar, PHP_EOL;
};
class MyClousre
{
public $callback;
private $privateVar = 123;
// 在类内部可以直接使用 $this
public function zbc(callable $callable)
{
// var_dump($callable);
$this->callback = $callable->bindTo($this, __CLASS__); // bindTo的作用是 将闭包绑定到指定的类 打通内部状态 是闭包中可以访问类的成员
// var_dump($callable);
}
public function zbcc()
{
call_user_func($this->callback);
($this->callback)();
}
}
$mc = new MyClousre();
$mc->zbc($abc);
// $mc->zbc([new Test(), 'aaa']); // 测试结果是 bindTo只能是用在Closure对象上
$mc->zbcc();
// class Test
// {
// public static function aaa()
// {
// echo $this->privateVar, PHP_EOL;
// }
// }
// 可以达到的效果 在闭包中使用对象中的各种成员
// 在类的外部 不能直接绑定$this 要先new
$cba = $cba->bindTo(new MyClousre(), MyClousre::class);
$cba();
// bind的使用
$foo = function () {
echo $this->zbc() . PHP_EOL;
};
class Haiyoushui
{
private function zbc()
{
return 'bayehelie';
}
}
$bar = Closure::bind($foo, new Haiyoushui(), Haiyoushui::class);
$bar();
发现错误欢迎指正,感谢~~
下期预告:composer下的各个文件内容的生成和意义及PSR-4示例讲解
最新文章
- 重温Servlet学习笔记--response对象
- lufylegend游戏引擎
- pyqt2_官网教程
- effective OC2.0 52阅读笔记(四 协议与分类)
- NSTimer定时器的使用
- Leetcode 之Populating Next Right Pointers in Each Node II(51)
- eclipse 和 android studio 快捷键对比
- shell 加减乘除
- oracle查锁表SQL
- PHP dirname() 返回路径中的目录部分basename() 函数返回路径中的文件名部分。
- git 拉取远程分之到本地
- android小知识之注释模板(转载)
- bnu 34982 Beautiful Garden(暴力)
- Pycharm中Django安装配置Mongodb
- 在UnrealEngine中用Custom节点实现描边效果
- 怎么检测浏览器有没有flash播放器
- Unity3D使用碰撞体做触发器实现简单的自己主动开门
- JS 同一标签随机不停切换数据点菜--解决选择困难症
- 【Py大法系列--01】20多行代码生成你的微信聊天机器人
- [SQL] 简单新建(create)删除(drop\delete)权限(grant/revoke)修改(set\update)