PHP 类的自动加载
以前看过这块的概念与讲解,知道通过composer构建的现代化框架都是通过spl_autoload_register函数进行类的自动加载,现在形成笔记记录一下
类的加载方式
手动引入
__autoload
spl_autoload_register
手动引入
就相当了刚开始学习php时的几个函数 include、include_once、require、require_once 。
寻找方式:
按参数给出的路径寻找
没有目录(只有文件名)按照include_path指定的目录去寻找
调用脚本文件所在目录和当前工作目录下寻找
include 实验:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php // 正常引入 $includeRes = include 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello(); // 错误引入 $includeRes = include 'AutoloadDemo1.php'; var_dump($includeRes); // 重复引入 $includeRes = include 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello();
结果:
1 2 3 4 5 6 7 8 9 10 11 // 正常引入 int(1) Hello AutoloadDemo // 错误引入 PHP Warning: include(AutoloadDemo1.php): failed to open stream: No such file or directory bool(false) // 重复引入 PHP Fatal error: Cannot declare class AutoloadDemo, because the name is already
include成功时,返回值为int(1),失败的返回值为bool(false)
错误引入是warning,重复引入是error
include_once 实验:
1 2 3 4 5 6 7 8 9 10 11 12 <?php // 正常引入 $includeRes = include_once 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello(); // 重复引入 $includeRes = include_once 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello();
1 2 3 4 5 6 7 8 9 10 11 12 <?php // 正常引入 $includeRes = include 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello(); // 重复引入 $includeRes = include_once 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello();
结果:
1 2 3 4 int(1) Hello AutoloadDemo bool(true) Hello AutoloadDemo
1 2 3 4 int(1) Hello AutoloadDemo bool(true) Hello AutoloadDemo
第一次引入成功时,都是返回的int(1)
重复引入时,会直接返回bool(true)
require 实验:
1 2 3 4 5 6 7 8 9 10 11 <?php // 正常引入 $includeRes = require 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello(); // 错误引入 $includeRes = require 'AutoloadDemo1.php'; var_dump($includeRes);
1 2 3 4 5 6 7 8 9 10 11 <?php // 正常引入 $includeRes = require 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello(); // 重复引入 $includeRes = require 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello();
结果:
1 2 3 4 5 int(1) Hello AutoloadDemo PHP Warning: require(AutoloadDemo1.php): failed to open stream: No such file or directory Fatal error: require(): Failed opening required 'AutoloadDemo1.php
1 2 3 int(1) Hello AutoloadDemo PHP Fatal error: Cannot declare class AutoloadDemo, because the name is already
成功引入时跟include一样,返回值都是int(1)
错误引入与重复引入,都会抛出error
require_once 实验:
1 2 3 4 5 6 7 8 9 10 11 <?php // 正常引入 $includeRes = require 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello(); // 重复引入 $includeRes = require_once 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello();
1 2 3 4 5 6 7 8 9 10 11 <?php // 正常引入 $includeRes = require_once 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello(); // 重复引入 $includeRes = require_once 'AutoloadDemo.php'; var_dump($includeRes); AutoloadDemo::hello();
结果:
1 2 3 4 int(1) Hello AutoloadDemo bool(true) Hello AutoloadDemo
1 2 3 4 int(1) Hello AutoloadDemo bool(true) Hello AutoloadDemo
区别
require一个文件存在错误的话,那么程序就会中断执行了,并显示致命错误。
include一个文件存在错误的话,那么程序不会中端,而是继续执行,并显示一个警告错误。
现在越来越趋向于严格的编码,所以require错误直接中断执行,才是可靠的
__autoload
__autoload() 在 PHP 7.2.0 起弃用,在 PHP 8.0.0 起移除。
简单示例一下就行了,毕竟现在已经没人用了吧
1 2 3 4 5 6 7 8 9 10 11 <?php function __autoload(string $classname) { $file = $classname . '.php'; if (file_exists($file)) { require_once $file; } } AutoloadDemo::hello();
遇到未包含的类,会触发 __autoload 进行加载,如果所有加载规则中没有此类,则 Fatal error。
不支持多个自动加载的函数。
spl_autoload_register
spl_autoload_register() 函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。通过注册自动加载器,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。 将函数注册到SPL autoload函数队列中。如果该队列中的函数尚未激活,则激活它们。如果在你的程序中已经实现了 autoload()函数,它必须显式注册到__autoload()队列中。
实验:
1 2 3 4 5 6 7 . ├── demo1 │ └── AutoloadDemo1.php ├── demo2 │ └── AutoloadDemo2.php └── spl_autoload_register.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php $autoload1 = function (string $classname) { $path = './demo1/' .$classname . '.php'; echo "尝试使用autoload1 加载类 {$classname}" .PHP_EOL; if (file_exists($path)) { require_once $path; } }; $autoload2 = function (string $classname) { $path = './demo2/' . $classname . '.php'; echo "尝试使用autoload2 加载类 {$classname}" .PHP_EOL; if (file_exists($path)) { require_once $path; } }; spl_autoload_register($autoload1); spl_autoload_register($autoload2); AutoloadDemo1::hello(); AutoloadDemo2::hello();
结果:
1 2 3 4 5 6 尝试使用autoload1 加载类 AutoloadDemo1 Hello AutoloadDemo1 尝试使用autoload1 加载类 AutoloadDemo2 尝试使用autoload2 加载类 AutoloadDemo2 Hello AutoloadDemo2
spl_autoload_register会维护一个autoload队列,可添加多个
当调用未知类时,触发autoload队列
依次调用注册的autoload队列,直到队列结束 或者 找到类
当使用 spl_autoload_register() 后当 new 一个未包含的类时候,会去执行 spl_autoload_register() 第一个参数函数名的函数,这个函数有一个参数就是需要 new 的类名,这个函数的功能就是把这个类给包含进来(类名和文件名一致),这样就实现了自动加载功能