自动加载(代码片段)

huachengai huachengai     2022-12-03     258

关键词:

thinkphp6&laravel7&swoft都使用了composer去加载类库。

访问框架的入口文件,框架的第一件事就是配置自动加载,这个是后面类的调用与实例化的基础工作。

为什么需要自动加载?

当使用未定义的类与接口时,自动去搜索并加载类文件。赶在php抛出错误前做最后的挣扎。

整个composer的实现原理是:首先将各个使用了不同psr规范的类或映射类,以某种形式存储,然后当类找不到的时候,通过与存储的数据匹配,找到类所在的路径,然后去加载。

自动加载,节省了人工去require/include的操作,提高了便捷性,但带来一定的性能损耗。

composer第三方类库就是实现这种功能,为什么大家都使用这个类库呢。下面探索一下这个类库代码,如何去寻找类文件。

技术图片

 

从上面的活动图可以看出,实际上composer总共有四种规范的文件需要加载。

分别是:psr0、psr4、类映射、公共函数文件。

现在通过代码去分析,composer的如何去实现的。

autoload.php文件,初始化ClassLoader类,也是整个加载流程的主角。

require_once __DIR__ . ‘/composer/autoload_real.php‘;

return ComposerAutoloaderInit35e14f048fbf9badf052d7e5a5050e37::getLoader();
<?php

// autoload_real.php @generated by Composer

// 类名的奇特,可理解为每个项目的加载文件都不一样,就像不同文件有不同的MD5一样。但是生成后就不再改变
class ComposerAutoloaderInit35e14f048fbf9badf052d7e5a5050e37

    private static $loader;

    public static function loadClassLoader($class)
    
        if (‘ComposerAutoloadClassLoader‘ === $class) 
            require __DIR__ . ‘/ClassLoader.php‘;
        
    

    // 使用了单例模式
    //原理:简化后,psr0,psr4,classmap每个分类对应一个数组,类名在这三个数组进行检索,检索完成后,include
    public static function getLoader()
    
        if (null !== self::$loader) 
            return self::$loader;
        

        //此处先注册自动加载未定义类,紧跟着注销,是因为只加载并实例化classLoader类,其他类的加载,使用composer提供的方法,而不是自定义的。
        spl_autoload_register(array(‘ComposerAutoloaderInit35e14f048fbf9badf052d7e5a5050e37‘, ‘loadClassLoader‘), true, true);
        self::$loader = $loader = new ComposerAutoloadClassLoader();
        spl_autoload_unregister(array(‘ComposerAutoloaderInit35e14f048fbf9badf052d7e5a5050e37‘, ‘loadClassLoader‘));

        //php版本大于5.6且未使用hhvm且没有启用zenGaurd加密扩展,即可使用静态加载
        // composer install 后, 从各个vendor库的composer.json中读取autoload属性。
        // 第一次就生成了静态文件
        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined(‘HHVM_VERSION‘) && (!function_exists(‘zend_loader_file_encoded‘) || !zend_loader_file_encoded());
        if ($useStaticLoader) 
            require_once __DIR__ . ‘/autoload_static.php‘;

            //getInitializer返回的是Closure类。该类是匿名函数的实现。因此可以被回调。
            call_user_func(ComposerAutoloadComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::getInitializer($loader));
         else 
            $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->register(true);

        // 自动加载文件,加载的是公共函数
        if ($useStaticLoader) 
            $includeFiles = ComposerAutoloadComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$files;
         else 
            $includeFiles = require __DIR__ . ‘/autoload_files.php‘;
        
        foreach ($includeFiles as $fileIdentifier => $file) 
            composerRequire35e14f048fbf9badf052d7e5a5050e37($fileIdentifier, $file);
        

        return $loader;
    


// 加载全局函数。可以通过全局变量查看哪个全局文件被加载了。
function composerRequire35e14f048fbf9badf052d7e5a5050e37($fileIdentifier, $file)

    if (empty($GLOBALS[‘__composer_autoload_files‘][$fileIdentifier])) 
        require $file;

        $GLOBALS[‘__composer_autoload_files‘][$fileIdentifier] = true;
    

这里使用到了一个技巧,若对象类的成员属性是private,同时已经实现了set方法,现在需要实现同样的功能,直接复制给private成员属性。若是常用方法是将private属性变成public,或者修改set方法,或添加新的方法。但这里使用了系统类Closure的属性,可以通过bind方法,使用到了目标对象的private属性。

autoload_static.php

    public static function getInitializer(ClassLoader $loader)
    
        //复制一个闭包,绑定ClassLoader作用域。可操作私有方法。直接赋值到数组,减少操作函数的次数。
        //初始化需要加载的类
        return Closure::bind(function () use ($loader) 
            $loader->prefixLengthsPsr4 = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$prefixDirsPsr4;
            $loader->fallbackDirsPsr4 = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$fallbackDirsPsr4;
            $loader->prefixesPsr0 = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$prefixesPsr0;
            $loader->classMap = ComposerStaticInit35e14f048fbf9badf052d7e5a5050e37::$classMap;

        , null, ClassLoader::class);
    

 psr0,psr4,可以首先查看具体的规范:

https://www.php-fig.org/psr/psr-4/

https://www.php-fig.org/psr/psr-0/

通俗地讲,psr0的路径就是在原先的命名空间前面添加新的路径名,类名遇到下划线_,还需转换成目录分隔符;psr4是使用路径替换掉命名空间前缀。

composer为了快速筛匹配,先过滤首字母,在匹配具体的命名空间。

技术图片

 

 技术图片

 

 

最后,使用了spl_autoload_register系统函数去配置用户自定义的加载函数,大大提高了便捷性。

 

php自动加载对象(代码片段)

查看详情

phpzendframework样式自动加载器(代码片段)

查看详情

php自动加载器类(代码片段)

查看详情

jsoncomposer.json自动加载冲突?(代码片段)

查看详情

jsoncomposer.json自动加载冲突?(代码片段)

查看详情

自动加载(代码片段)

...载类库。访问框架的入口文件,框架的第一件事就是配置自动加载,这个是后面类的调用与实例化的基础工作。为什么需要自动加载?当使用未定义的类与接口时,自动去搜索并加载类文件。赶在php抛出错误前做最后的挣扎。整... 查看详情

php使用composer自动加载器(代码片段)

查看详情

php使用自动加载与pear(代码片段)

查看详情

php自动加载类和函数(代码片段)

查看详情

springboot初始加载自动配置类(代码片段)

springboot初始加载自动配置类@SpringBootApplication-->@EnableAutoConfiguration@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfigu 查看详情

php#laravel中的自动加载帮助程序(代码片段)

查看详情

php自动加载autoload和命名空的应用(代码片段)

阅读目录阐述1.自动加载的原理以及`__autoload`的使用2.`spl_autoload_register`自动加载3.`spl_autoload_register`自动加载和`namespace`命名空间阐述PHP的自动加载就是我们加载实例化类的时候,不需要手动去写require来导入这个class.php文件,程... 查看详情

php使用js自定义自动页面重新加载(代码片段)

查看详情

markdown带有自动加载器的php类框架(代码片段)

查看详情

javascript具有重新加载功能的slidedeck自动播放(代码片段)

查看详情

php使用php自动加载目录中的文件(代码片段)

查看详情

滚动到底部自动加载新内容(代码片段)

$(window).on(‘scroll‘,function()if($(window).height()+$(window).scrollTop()>=$(document).height())console.log("到达底部");     //这里是要加载的数据);console.log(‘整个网页的高度‘+$(document).height());//整个网页的高度cons 查看详情

自动加载简单实现__autoload()(代码片段)

./index.php入口文件function__autoload($classname)$filename="./".$classname.".php";include_once($filename);//we‘vecalledaclass***$obj=newmyClass();//myClass.phpclassmyClasspublicfunction__construct()ec 查看详情