浅谈PSR规范与PHP框架中类的自动加载原理

浅谈PSR规范与PHP框架中类的自动加载原理

在PHP中,如果要实例化的类不在当前文件中,那么需要require引入类所在的文件。但在项目编程中,频繁因此引入文件十分影响开发效率,因此诞生了PHP类自动加载方法。

__autoload()函数(不推荐)

__autoload是早期的自动加载方法,用户可以重新定义这个方法。在文件中调用一个不存在的类会在报错前自动调用此方法,用户可以在方法内定义自动加载逻辑。

function __autoload($class){
    require_once $class.'.php';
}

//当Class类不存在时自动调用__autoload函数,传入参数'Class'
$class = new Class();

这种自动加载方式目前已不被推荐,未来可能被弃用。

spl_autoload_register()注册自动加载器

PHP5以后, spl_autoload_register() 函数可以注册任意数量的自动加载器,当调用未定义的类时调用自动加载器的方法,代替__autoload的作用。

function autoload($class){
    require_once $class.'.php';
}

spl_autoload_register('autoload');  //将autoload函数注册为自动加载器

//当Class类不存在时自动调用autoload('Class');
$class = new Class();

PSR规范与框架自动加载原理

目前绝大多数框架都是遵循PSR规范,然后通过注册自己的自动加载器实现自动加载。

PSR0规范

  • 一个完全标准的命名空间(namespace)和类(class)的结构是这样的:\()*
  • 每个命名空间(namespace)都必须有一个顶级的空间名(namespace)(“组织名(Vendor Name)”)。
  • 每个命名空间(namespace)中可以根据需要使用任意数量的子命名空间(sub-namespace)。
  • 从文件系统中加载源文件时,空间名(namespace)中的分隔符将被转换为 DIRECTORY_SEPARATOR。
  • 类名(class name)中的每个下划线都将被转换为一个DIRECTORY_SEPARATOR。下划线在空间名(namespace)中没有什么特殊的意义。
  • 完全标准的命名空间(namespace)和类(class)从文件系统加载源文件时将会加上.php后缀。
  • 组织名(vendor name),空间名(namespace),类名(class name)都由大小写字母组合而成。

    以上大致可以理解为: 一个类所在的命名空间与类所在文件相对项目跟目录路径相对应。

    例如一个项目目录结构如下:
    这里写图片描述

User类所在文件user.php相对于项目根目录路径是 ./app/index/controller/user.php 那么遵从psr规范,User类所在命名空间应定义为: namespace app\index\controller

遵从psr规则后,便可以类似下方代码注册自动加载器:

function autoLoad($class)  
{  
    $class = strtr($class, '\\', '/');  
    $file = APP_PATH . '/' . strtolower($class) . '.php';  
    if (is_file($file)) {  
        require $file;  
    } else {  
        $arr = explode('/', $class);  
        throw new \Exception\Error('目标文件' . htmlspecialchars(end($arr)) . ' 不存在', 404);  
    }  
}  
spl_autoload_register('autoLoad');  

自动加载流程如下:

在user.php中自动调用Base类

Base 类命名空间与 User 类相同

namespace app\index\controller

class User extends Base{
    ...
}

//本命名空间下Base类不存在,自动调用 app\index\controller\Base类,相当于调用函数 autoLoad('app\index\controller\Base');

*在user.php 中调用model\user

namespace app\index\controller
use app\common\model\User

class User extends Base{
    $model = new User();
}

//使用use引入类,new User相当于 new app\common\model\User();
//此时传入autoLoad的参数为 'app\common\model\User';
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章