composer分析(一)

本文内容

  • 基于PSR-4规范的自动加载 请结合文档和下面的代码注释
  • spl_autoload_register
  • php闭包Closure简单用法(大体使用情景: 生成回调提供使用, 使用闭包绑定类中的成员属性和方法)

  1. 框架引入composer自动加载器

    require __DIR__ . '/../vendor/autoload.php';
  2. autoload.php文件内容

    <?php
    
    // autoload.php @generated by Composer
    
    require_once __DIR__ . '/composer/autoload_real.php';
    
    // 返回自动加载器 object(Composer\Autoload\ClassLoader)
    return ComposerAutoloaderInit251f259405d38ea713d5c2b4f861292a::getLoader();
  3. 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;
    }
  4. 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);
    }
  5. 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示例讲解

composer源码简单分析(一)的更多相关文章

  1. FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  2. FFmpeg源码简单分析:libswscale的sws_scale()

    ===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...

  3. Django-session中间件源码简单分析

    Django-session中间件源码简单分析 settings里有关中间件的配置 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddlew ...

  4. FFmpeg源码简单分析:结构体成员管理系统-AVOption

    ===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...

  5. negroni-gzip源码简单分析解读

    negroni-gzip源码简单分析解读 这是一个为Negroni设计的gzip压缩处理中间件,需要用到已有的compress中的gzip,阅读了不长的源码之后,总结了一些关键要点和注意点. 检查是否 ...

  6. FFmpeg的HEVC解码器源码简单分析:概述

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  7. FFmpeg的HEVC解码器源码简单分析:解码器主干部分

    ===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...

  8. urllib源码简单分析

    对下面这段代码做分析 import urllib params = urllib.urlencode({'wd': 'python'}) f = urllib.urlopen("http:/ ...

  9. CardboardSDK-iOS 源码简单分析

    该项目地址: 地址 克隆地址为 https://github.com/rsanchezsaez/CardboardSDK-iOS.git 目前如果想在iOS设备上实现双目VR的功能,Google 已经 ...

随机推荐

  1. luogu P2973 [USACO10HOL]Driving Out the Piggies G 驱逐猪猡

    luogu LINK:驱逐猪猡 bzoj LINK:猪猪快跑 问题是在1时刻有个炸蛋在1号点 这个炸弹有p/q的概率爆炸 如果没有爆炸 那么会有1/di的概率选择一条边跳到另外一个点上重复这个过程. ...

  2. 学习java 线程池-1: ThreadPoolExecutor

    1. Executor 该接口内只有一个接口方法 :该方法的目的就是执行指定的 Runnable (但会不会执行,或者会不会立马执行,则不一定.因为要取决于整个线程池的状态) Executor 中文的 ...

  3. java进阶(2)--抽象类

    一.抽象类集刺虎: 1.概念 类与类之前有共同特征,将这些共同特征提取出来,行为抽象类   2.抽象类的数据类型: 引用数据类型   3.语法 [修饰符列表]abstract Class 类型{类体} ...

  4. 【NOIP2017】跳房子 题解(单调队列优化线性DP)

    前言:把鸽了1个月的博客补上 ----------------- 题目链接 题目大意:机器人的灵敏性为$d$.每次可以花费$g$个金币来改造机器人,那么机器人向右跳的范围为$[min(d-g,1),m ...

  5. C++STL算法

    1.不变序列算法 不会修改算法所作用的容器或对象 适用于顺序容器和关联容器,时间复杂度为O(n). 2.变值算法 会修改源区间或目标区间元素的值,值被修改的那个区间,不可属于关联容器. 3.删除算法 ...

  6. QWebEngineView简单使用

    QWebEngineView是提供一个访问web页面的widget,这里是一个简单的使用代码 头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H #includ ...

  7. WebMvcConfigurerAdapter在2.x向上过时问题

    在spring boot2.x向上,书写配置类时集成的WebMvcConfigurerAdapter会显示此类已经过时. 解决:不继承WebMvcConfigurerAdapter类,该实现WebMv ...

  8. ConHost.exe机制

  9. 【lhyaaa】2020深圳大湾区比赛总结

    又名花样丢分锦集 首先,我们需要来吐槽一下垃圾szccf,毁我青春 居然没有提醒不能用万能头文件,导致一题爆0,据说还有一些结果不是自己答的 emmm-- 进正题 选择题 对包含n个数的序列进行冒泡排 ...

  10. SCHP代码中的问题

    1.subprocess.CalledProcessError: Command ‘[‘where’, ‘cl’]’ returned non-zero exit status 1. 这个问题是因为电 ...