zoukankan      html  css  js  c++  java
  • php自动加载规范 PSR4 (Thinkphp)

    PSR4是一种自动加载规范,老版本是PSR0,尽管thinkPHP支持PSR4和PSR0的自动加载方式,但是默认也是优先进行PSR4加载,如果失败,再进行PSR0的加载。本篇文章只会讨论PSR4的加载。

    代码示例:

    spl_autoload_register(function ($class) {
    
        // 指定项目的命名空间前缀
        $prefix = 'Foo\Bar\';
    
        // 指定项目的根目录
        $base_dir = __DIR__ . '/src/';
    
        // 判断类的前缀是不是上面的命名空间前缀
        $len = strlen($prefix);
        if (strncmp($prefix, $class, $len) !== 0) {
            // 不是,则交给其他类加载器去加载,不使用PSR4
            return;
        }
    
        // 获取相对的命名空间
        $relative_class = substr($class, $len);
    
        // replace the namespace prefix with the base directory, replace namespace
        // separators with directory separators in the relative class name, append
        // with .php
        // 使用根目录替换命名空间前缀,使用目录分隔符替换相对类名中的命名空间分隔符,然后再加上.php
        $file = $base_dir . str_replace('\', '/', $relative_class) . '.php';
    
        // 如果该类存在,则require它
        if (file_exists($file)) {
            require $file;
        }
    });

    从上面的代码中,我们就可以知道PSR4到底是干什么的。
    这个规范主要就是将类转换成物理路径。

    1. 命名空间前缀使用根目录替换
    2. 去掉命名空间前缀剩下的部分,叫做它相对类名
    3. 使用目录分隔符替换掉相对类名中的命名空间分隔符(也就是变成/)
    4. 加上.php

    比如thinkphp典型的一个控制器:Index.php

    <?php
    namespace appindexcontroller;
    
    class Index{
    }
    

    那么在加载的时候,传给这个PSR4的时候,$class=appindexcontrollerIndex;

    假设当前的根目录为:E:app
    当前的命名空间前缀为:app
    根据前面的转换步骤,这个类的路径应该是在:
    E:/app/index/controller/Index.php

    路径的斜杆(/)跟反斜杆()。在windows中通常是使用反斜杆作为路径分隔符的,而在linux中,通过是使用斜杆作为路径分隔符的。不过windows现在的API都支持使用斜杆作为路径分隔符了,而如果使用反斜杆的话,那么在单引号中,还需要写成才能当成。而linux中是使用/,因此我们的路径表示便是使用斜杆了。

    有同学跟我反映说,php单引号不是不会被转义吗?这个确实是,不过对于要输出单引号,因此在单引号字符串中,单引号是需要使用反斜杆转义才能输出的,而反斜杆本身也是需要使用反斜杆来转义,对于其他的转义,就真的不会了。

    thinkphp5的类加载

    类库映射实际上就是保存一个键值对数组,键值为类名,值为物理路径,这样当类加载的时候,直接查找该数组就行。

    而对于PSR4,我们根据上面知道,需要注册根目录跟命名空间前缀。
    在thinkphp中注册了五个命名空间前缀:

    self::addNamespace([
                'think'    => LIB_PATH . 'think' . DS,
                'behavior' => LIB_PATH . 'behavior' . DS,
                'traits'   => LIB_PATH . 'traits' . DS,
            ]);
    

    还有两个是可以配置的:

    self::$namespace = $config['app_namespace'];
                Loader::addNamespace($config['app_namespace'], APP_PATH);
                if (!empty($config['root_namespace'])) {
                    Loader::addNamespace($config['root_namespace']);
                }
    

    因此在配置文件中的app_namespace就是指明应用的命名空间前缀。比如默认为app对应着跟目录为application。

    PSR4的备选目录

    当使用PSR4方式读取失败的话,那么还有备选的目录可以用来读取,thinkphp便是使用这种方式作为扩展目录的读取:

    // 查找 PSR-4 fallback dirs
            foreach (self::$fallbackDirsPsr4 as $dir) {
                if (is_file($file = $dir . DS . $logicalPathPsr4)) {
                    return $file;
                }
            }
    

    $logicalPathPsr4就是这事将命名空间分隔符转换为目录分隔符再加上.php而已。

    不过,通常来说,开源的扩展应该使用composer开发。而只有私人的扩展,一般才放在extend目录下的。

    为什么TP不完全使用composer的加载器呢?
    一是完全基于composer的话,那么当composer更新的时候,框架也需要相对应地调整,因此不能够完全地专注于框架的开发。二如果完全抛弃composer而专注于框架,又像是捡了芝麻丢了西瓜。因此将composer作为框架的延伸扩展,无疑是一种比较好的折中方案。


    原文链接:https://www.kancloud.cn/code7/tp5/343057
  • 相关阅读:
    iOS中使用nil NULL NSNULL的区别
    Xcode常用快捷键总结
    (求租仓库)navigationController .navigationBar 的属性设置
    imageNamed 与 initWithContentsOfFile 区别
    iOS-Senior10-多线程(子线程创建)
    iOS-setValue和setObject的区别
    iOS-Senior8-网络之进阶
    iOS-Senior7-数据请求
    iOS-Senior6-数据解析(JSON)
    iOS-Senior6-数据解析(XML)
  • 原文地址:https://www.cnblogs.com/skl-bobo/p/10432438.html
Copyright © 2011-2022 走看看