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. 加载Properties文件工具类:LoadConfig

    import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; impor ...

  2. Sharding-JDBC实现读写分离

    参考资料:猿天地  https://mp.weixin.qq.com/s/kp2lJHpTMz4bDWkJYjVbOQ  作者:尹吉欢 技术选型:SpringBoot + Sharding-JDBC ...

  3. eureka注册中心的使用

    1.父pom.xml中引入springcloud依赖 <dependencyManagement> <dependencies> <dependency> < ...

  4. 一道 3 行代码的 Python面试题,我懵逼了一天

    有意思的题目 题目:写出下面程序运行结果 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的 ...

  5. Python-关于正则表达式的总结

    什么是正则表达式? 正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),用于字符串的 匹配 和 提取 等操作.正则表达式在所有编程语言中都是通用的. 很多人 ...

  6. JDK 1.8 中文 API CHM

    链接: https://pan.baidu.com/s/1AiJn6RM1KoEL1n_96qoQhQ 提取码: n2ya

  7. Java中的引用与ThreadLocal

    Java中的引用--强软弱虚 强引用 Object object = new Object(),这个object就是一个强引用.如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回 ...

  8. java SFTP工具类

    需要导入jsch-0.1.52.jar import java.io.File; import java.io.FileInputStream; import java.io.FileOutputSt ...

  9. 一篇看懂Socket开发

    Socket[套接字]是什么,对于这个问题,初次接触的开发人员一般以为他只是一个通讯工具. Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发 T ...

  10. 从一次外卖到对oauth2.0的思考

    别问oauth1.0哪去了,问就是不好讲. 1. 外卖并不好吃   今天下班得早,想吃顿好的,于是就点了一份外卖,过了一会儿,外卖到了,但是在小区大门被堵住了,我亲自远程开门后才能进来,又过了一会,被 ...