zoukankan      html  css  js  c++  java
  • Composer 的autoload 实现

     一、全局安装

    curl -sS https://getcomposer.org/installer | php
    mv composer.phar /usr/local/bin/composer

     https://docs.phpcomposer.com/00-intro.html

    二、代码

    require_once './vendor/autoload.php';
    
    一、autoload.php
       加载 composer/autoload_real.php 调用 autoload_real.php 下的 getLoader() 方法
       
    二、autoload_real.php
        getLoader() 方法
            创建 composerClassLoader.php 的对象 $loader
    
            1、静态调用 $useStaticLoader
                 加载 composerautoload_static.php
                 回调 autoload_static.php 下的 getInitializer($loader) 方法
    
                     getInitializer() 方法
                     通过匿名函数绑定,为$loader 对象下的私有属性赋值
                     $prefixLengthsPsr4,
                     $prefixDirsPsr4,
                     $prefixDirsPsr4,
                     $classMap
    
                 注册自动加载 $loader->register(true);
    
           spl_autoload_register([$this, 'loadClass', true, $prepend]);
    
           function loadClass($class) {
                if ($file = $this->findFile($class)) {
                    includeFile($file)
                    return true;
                }
           }
    
         // ClassLoader.php 下的方法
           public function findFile($class)
           {
               // class map lookup
               if (isset($this->classMap[$class])) {
                   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;
           }
    
           function includeFile($file)
                       {
                       include $file;
           }
    
        private function findFileWithExtension($class, $ext)
            {
                // PSR-4 lookup
                $logicalPathPsr4 = strtr($class, '\', DIRECTORY_SEPARATOR) . $ext;
    
                $first = $class[0];
                if (isset($this->prefixLengthsPsr4[$first])) {
                    $subPath = $class;
                    while (false !== $lastPos = strrpos($subPath, '\')) {
                        $subPath = substr($subPath, 0, $lastPos);
                        $search = $subPath . '\';
                        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;
                    }
                }
    
                // PSR-0 lookup
                if (false !== $pos = strrpos($class, '\')) {
                    // namespaced class name
                    $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                        . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
                } else {
                    // PEAR-like class name
                    $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
                }
    
                if (isset($this->prefixesPsr0[$first])) {
                    foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                        if (0 === strpos($class, $prefix)) {
                            foreach ($dirs as $dir) {
                                if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                                    return $file;
                                }
                            }
                        }
                    }
                }
    
                // PSR-0 fallback dirs
                foreach ($this->fallbackDirsPsr0 as $dir) {
                    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                        return $file;
                    }
                }
    
                // PSR-0 include paths.
                if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
                    return $file;
                }
    
                return false;
            }
    
           2、非静态调用
              略
    call_user_func(ComposerAutoloadComposerStaticInitd16dd22c4a12ecb92b3a245dff71e1fc::getInitializer($loader));
    
    public static function getInitializer(ClassLoader $loader)
        {
            return Closure::bind(function () use ($loader) {
                $loader->prefixLengthsPsr4 = ComposerStaticInitd16dd22c4a12ecb92b3a245dff71e1fc::$prefixLengthsPsr4;
                $loader->prefixDirsPsr4 = ComposerStaticInitd16dd22c4a12ecb92b3a245dff71e1fc::$prefixDirsPsr4;
                $loader->prefixesPsr0 = ComposerStaticInitd16dd22c4a12ecb92b3a245dff71e1fc::$prefixesPsr0;
                $loader->classMap = ComposerStaticInitd16dd22c4a12ecb92b3a245dff71e1fc::$classMap;
    
            }, null, ClassLoader::class);
        }
    
    解读:
    call_user_func+Closure::bind()的模式,其实这里我们也可以完全按照常规的做法,引入一个配置文件的方式来实现,Closure::bind()返回一个Closure对象,即一个闭包函数,其中一共有三个参数:
    
    closure:需要绑定的匿名函数
    
    newthis:需要绑定到匿名函数的对象,或者 NULL 创建未绑定的闭包
    
    newscope:想要绑定给闭包的类作用域,或者 'static' 表示不改变。如果传入一个对象,则使用这个对象的类型名。
    
    第一个参数好理解,第二个和第三个可以配合起来使用,当我们需要在闭包函数中使用$this的时候,我们需要给这个闭包绑定一个对象,如果闭包中使用了$this,那么newthis需要指定一个对应的对象;如果修改的属性是protected或者private,那么第三个参数不能忽略,指定为这个类。
    
    例1:
    
    class A{
        public $name;
        protected $age;
    }
    $a = new A();
    $new_a = Closure::bind(function(){
        $this->name = 'nine';
    } , null);
    $new_a();
    var_dump($new_a , $a);
    此时会报错Using $this when not in object context in ...,说明这个上下文并没有指定$this。
    
    例2:
    
    class A{
        public $name;
        protected $age;
    }
    $a = new A();
    $new_a = Closure::bind(function(){
        $this->name = 'nine';
        $this->age = 10;
    } , $a);
    $new_a();
    var_dump($new_a , $a);
    此时会报错Cannot access protected property A::$age in...,属性是受保护的。
    
    例3:
    
    class A{
        public $name;
        protected $age;
    }
    $a = new A();
    $new_a = Closure::bind(function(){
        $this->name = 'nine';
        $this->age = 10;
    } , $a , A::class);
    $new_a();
    var_dump($new_a , $a);
    设置成功。
     
  • 相关阅读:
    如何删除PeopleSoft Process Definition
    你真的了解PeopleSoft中的function和method方法嘛
    PeopleCode事件和方法只用于online界面不能用于组件接口(component interface)
    Lucene.Net 3.0.3如何从TokenStream中获取token对象
    从零开始搭建一个简单的基于webpack的vue开发环境
    Vue路由懒加载
    减少打包组件vue.config.js——Webpack的externals的使用
    axios全局配置及拦截器
    vue-cli中eslint配置
    DDD领域驱动设计基本理论知识总结
  • 原文地址:https://www.cnblogs.com/cshaptx4869/p/10538256.html
Copyright © 2011-2022 走看看