阅读模式:

php类的自动加载

查看:669  :0  类型:  来源:php自学网  标签 php设计模式

    当php面向对象开发过程中,随着项目越来越大,需要通过include或require引入的文件越来越多,每个php脚本开头都要引入一大堆文件引入,不便于项目的管理,当有类更新时,也容易导致项目出现报错。所以就需要类的自动载入功能。php通过__autoloadspl_autoload_register函数来实现。__autoload函数在PHP 7.2中已经废弃,不推荐使用。

一、__autoload

    当一个类实例化时会把类名以参数方式传给_autoload函数,spl_autoload_register也一样。然后通过目录+类名的方式引入文件。

    不使用自动加载时引入文件:

require 'a.php'; // class name a
require 'b.php'; // class name b
require 'c.php'; // class name c

    使用自动加载时引入文件,假设目录为/test:

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

$a = new a(); // 类名a即__autoload参数名 $class = a
$a = new b(); // $class = b
$a = new c(); // $class = c

二、spl_autoload_register

    当项目有多个模块时,__autoload不能满足需求,__autoload只能定义一次。如果需要多次使用autoload 函数时,spl_autoload_register() 满足了此类需求。 它实际上创建了 autoload 函数的队列,按定义时的顺序逐个执行。spl_autoload_register将函数注册到SPL __autoload函数队列中。如果该队列中的函数尚未激活,则激活它们。

   1.加载一个模块,匿名函数方式

spl_autoload_register(function ($class) {
    require __DIR__ . '/class/' . $class . '.class.php';
});

   2.加载多模块时,注册多个自定义自动装载函数

spl_autoload_register('homeAutoloader');
spl_autoload_register('adminAutoloader');

function homeAutoloader($class) {
    require_once __DIR__ . '/Home/class/' . $class . '.class.php';
}
function adminAutoloader($class) {
    require_once __DIR__ . '/Admin/class/' . $class . '.class.php';
}

    这时只要实例化后的类都会在一个队列中,如:

require_once __DIR__ . '/Home/class/index.class.php';
require_once __DIR__ . '/Home/class/edit.class.php';

require_once __DIR__ . '/Admin/class/index.class.php';
require_once __DIR__ . '/Admin/class/index.class.php';

    上面的方式虽然实现了类的自动加载,但当出现同样的类名,就会报错。所以需要引入一些规范和命名空间来解决。

   3.类自动加载PSR规范

    PSR 是 PHP Standard Recommendations 的简写,由 PHP FIG 组织制定的 PHP 规范,是 PHP 开发的实践标准。现在的标准是PSR-4规范,在此之前还有PSR-1、PSR-2、PSR-3规范,PSR-1规范已弃用。PSR-4规范是在PSR-1、PSR-2规范中更新和扩展而来。

    PSR-1规范要求(已弃用):

*命名空间结构必须时由 \vendor Name\Namespace\Class Name 结构组成,即:\app\controller\Index,Vendor Name 为每个命名空间都必须要有的一个顶级命名空间名,vendor Name、Namespace、Class Name可由任意大小写字母组成;

*命名空间结构必须是路径的一部分;

*类名称中的每个 _ 字符也会被转换成文件夹路径分隔符;即:\app\controller\Index_Index 。index目录中的index.php类,用下划线间隔;

*类文件名必须是 .php 后缀;

    PSR-2规范要求:

*代码 必须 遵循PSR-1中的编码规范;

*代码 必须 使用 4 个空格符进行缩进;

*每行的字符数应该软性保持在 80 个之内;

*namespace命名空间声明语句和 use 声明语句块后面必须 插入一个空白行;

*类和类中的方法开始花括号{和结束花括号}必须独自占有用一行;

*类的属性和方法 必须 添加访问修饰符(private、protected 以及 public),abstract 以及 final 必须 声明在访问修饰符之前,而 static 必须 声明在访问修饰符之后;

*控制结构的关键字后 必须 要有一个空格符,而调用方法或函数时不用空格;

*控制结构的开始花括号{必须 写在声明的同一行,而结束花括号}必须 写在主体后自成一行;

*控制结构的开始左括号后和结束右括号前不能有空格符;

    PSR-3规范要求:

psr-3规范制定了日志类库的通用接口规范。和这里自动加载关系不大,这里不作介绍。

    PSR-4规范要求:

*「class」指的是类(classes)、接口(interfaces)、特征(traits)和其他类似的结构。

*全限定类名具有以下形式:\NamespaceName\SubNamespaceNames\ClassName;

*全限定类名必须拥有一个顶级命名空间名称,也称为供应商命名空间(vendor namespace);

*全限定类名可以有一个或者多个子命名空间名称;

*全限定类名必须有一个最终的类名,不能是这样的形势 \NamespaceName\SubNamespaceNames*\;

*去除了psr-1中的下划线来间隔文件夹和文件名,下划线在psr-4中无意义;

*全限定类名可以是任意大小写字母的组合;

*所有类名的引用必须区分大小写;

*全限定类名的加载过程:

    *在全限定的类名(一个「命名空间前缀」)中,一个或多个前导命名空间和子命名空间组成的连续命名空间,不包括前导命名空间的分隔符,至少对应一个「根目录」;

    *「命名空间前缀」后面的相邻子命名空间与根目录下的目录名称相对应(且必须区分大小写),其中命名空间的分隔符表示目录分隔符;

    *最终的类名与以.php 结尾的文件名保持一致,这个文件的名字必须和最终的类名相匹配(意思就是如果类名是 FooController,那么这个类所在的文件名必须是 FooController.php);

*自动加载文件禁止抛出异常,禁止出现任何级别的错误,也不建议有返回值;

    psr全规范参考:https://learnku.com/docs/psr

  4.实现一个简单的mvc类的自动加载

   目录结构:

-----------------------------------------

app                             // 应用目录

    controller               // 控制器目录

        index

            Index.php       // Index控制器

        test

            Test.php         // Test模型

    model                   // 模型目录

        index

            Index.php     // index模型

    view                      // 视图目录

loader.php               // 自动加载类

index.php                // 入口文件

-----------------------------------------

执行过程:在入口index.php文件中引入自动加载类文件并调用。每次调用类方法时,通过spl_autoload_register函数穿类名路径的方式,处理后引用类文件。

php autoload mvc.png

    详细代码:

  入口Index.php

<?php
define('BASE_DIR', __DIR__);

// 引入自动加载
require __DIR__ . '/' . 'loader.php';
Loader::autoLoad();

// 调用Index控制器中index方法
\app\controller\index\Index::index();

// 调用Test控制器中test方法
\app\controller\test\Test::test();

  自动加载类loader.php

<?php
/**
 * 类的自动加载
 * Class Loader
 */
class Loader
{
    public static function autoLoad()
    {
        // 注册类
        spl_autoload_register(function ($class) {
            $class = str_replace('\\', DIRECTORY_SEPARATOR, $class);
            $filePath = BASE_DIR . DIRECTORY_SEPARATOR . $class . '.php';
            if (file_exists($filePath)) {
                include $filePath;
            } else {
                echo 'Class Not Found !';
            }
        });
    }
}

  控制器Index.php

<?php
namespace app\controller\index;

class Index
{
    public static function index()
    {
        echo 'Index.php: Index Controller' . "<br/>";
    }
}

  控制器Test.php

<?php
namespace app\controller\test;

use \app\model\index\Index as IndexModel;

class Test
{
    public static function test()
    {
        echo 'Test.php: Test Controller'  . ' ';

        // 控制器调用模型
        IndexModel::index();
    }
}

  模型Index.php

<?php
namespace app\model\index;

class Index
{
    public static function index()
    {
        echo 'Call Index Model ' . "<br/>";
    }
}

  运行结果:

autoload mvc res.png

代码下载:

audoLoad_mvc.zip

分享到:
1 0

我的看法:

IN: