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. markdown利器-小书匠

    markdown利器-小书匠 为什么要用markdown语法编写文档? 编写文档的好处这里就不多说了.相信很多人都会在一些博客网站上发布自己的博客,那么怎么能使得自己的博客内容更加具有通用性呢?正如j ...

  2. 打造静态分析器(二)基于Asp.Net Core 3.0的AspectCore组件检测

    上一篇,我们打造了一个简单的分析器,但是我们实际使用分析器就是为了对项目做分析检测,增加一些非语法的自检的 比如Asp.Net Core 3.0的替换依赖注入检测 设计分析 我们创建一个默认的Asp. ...

  3. Android Studio连接数据库实现增删改查

    源代码如下: DBUtil.java: package dao; import java.sql.Connection; import java.sql.DriverManager; import j ...

  4. 【模式识别与机器学习】——SVM举例

  5. Vue $nextTick的一个使用场景

    $nextTick 官方解释 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM 使用场景 在页面上有2个表单元素和2个按钮 btnRequiredFi ...

  6. printf函数和putchar函数

    #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib. ...

  7. Oracle从回收站找回误删的数据

    Step1 先根据删除时间查看删除了那些表 select * from recyclebin where type = 'TABLE' and createtime like '${删除时间}%' o ...

  8. Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for

    Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value f ...

  9. Mac 从睡眠恢复后没有声音的问题

    重启能解决,不想重启,因为不想重置当前工作状态 换个办法是: 杀掉coreaudiod进程,然后系统会把他自动拉起,然后就ok了.

  10. c/c++ 感悟 2008-10-03 02:08

    许久没有坐在电脑前写东西了.除了密密麻麻的英文小虫子,还是英文小虫子.今天不是解决bug,明天就是在创造bug,一句话不在bug中沉默就在bug中爆发.或许喜欢小宇宙爆发的样子吧,那样的感觉总是让人热 ...