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示例讲解

最新文章

  1. 重温Servlet学习笔记--response对象
  2. lufylegend游戏引擎
  3. pyqt2_官网教程
  4. effective OC2.0 52阅读笔记(四 协议与分类)
  5. NSTimer定时器的使用
  6. Leetcode 之Populating Next Right Pointers in Each Node II(51)
  7. eclipse 和 android studio 快捷键对比
  8. shell 加减乘除
  9. oracle查锁表SQL
  10. PHP dirname() 返回路径中的目录部分basename() 函数返回路径中的文件名部分。
  11. git 拉取远程分之到本地
  12. android小知识之注释模板(转载)
  13. bnu 34982 Beautiful Garden(暴力)
  14. Pycharm中Django安装配置Mongodb
  15. 在UnrealEngine中用Custom节点实现描边效果
  16. 怎么检测浏览器有没有flash播放器
  17. Unity3D使用碰撞体做触发器实现简单的自己主动开门
  18. JS 同一标签随机不停切换数据点菜--解决选择困难症
  19. 【Py大法系列--01】20多行代码生成你的微信聊天机器人
  20. [SQL] 简单新建(create)删除(drop\delete)权限(grant/revoke)修改(set\update)

热门文章

  1. AutoWired注解和Lazy延迟加载
  2. Java线程知识:二、锁的简单使用
  3. 038_go语言中的状态协程
  4. 再见,付费录屏软件!我用70行Python代码打造免费版!
  5. Linux 安装 PostgreSQL
  6. The Involution Principle
  7. Ambiguous mapping. Cannot map &#39;xxxController&#39; method
  8. mysql的ATM存取款机系统
  9. python设计模式之享元模式
  10. noip复习——快速幂