昨天面试被问到了 PHP 的自动加载机制,因为很多概念模糊啦,没回答好,今天特意来总结一下。
include 和 require 是PHP中引入文件的两个基本方法,但是每个脚本的开头,都需要包含(include)一个长长的列表总是不好的,所以 PHP 使用了自动加载器来解决这个问题。
PHP 自动加载
实现自动加载的两种方式
- __autoload() 尝试加载未定义的类(因为只可以定义一次,不再建议使用 __autoload() 函数,在以后的版本中它可能被弃用)
- spl_autoload_register() 提供了一种更加灵活的方式来实现类的自动加载(同一个应用中,支持任意数量的加载器,比如第三方库中的)。
spl_autoload_register 方式
功能:就是把传入的参数(可以为回调函数或函数名称)注册到 SPL __autoload 函数队列中。如果在你的程序中已经实现了 __autoload 函数,它必须显式注册到队列中。(PHP 5 >= 5.1.0, PHP 7)
参数介绍:
- autoload_function:回调函数或者函数名称形式,如果没有提供任何参数,则自动注册 autoload 的默认实现函数。
- throw:
autoload_function
无法成功注册时, spl_autoload_register()是否抛出异常。 - prepend:如果是 true,spl_autoload_register() 会添加函数到队列之首,而不是队列尾部。
1 <?php 2 namespace Foobar; 3 4 class Foo { 5 static public function test($name) { 6 print '[['. $name .']]'; 7 } 8 } 9 spl_autoload_register(__NAMESPACE__ .'Foo::test'); // 自 PHP 5.3.0 起 10 11 new InexistentClass; 12 13 ?>
输出示例:
[[FoobarInexistentClass]] Fatal error: Class 'FoobarInexistentClass' not found in ...
上述代码:将 Foo 的静态方法 test 注册到自动加载队列中,通过上面的示例可以看到 自动加载的运行过程,既:当需要使用的类没有被引入时,这个函数会在PHP报错前被触发。
函数里面的具体逻辑要根据我们的具体情况实现,就上面的问题而言,引入的函数需要同样在 Foobar 的命名空间之下,并且声明 InexistentClass 对象。(PSR-4 是关于由文件路径自动载入对应类的相关规范)。
PHP 中 USE 关键字介绍
use 关键字作用
为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名。
PHP 7 可以使用一个 use 从同一个 namespace 中导入类、函数和常量。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // PHP 7 之前版本需要使用多次 use 2 use some amespaceClassA; 3 use some amespaceClassB; 4 use some amespaceClassC as C; 5 6 use function some amespacefn_a; 7 use function some amespacefn_b; 8 use function some amespacefn_c; 9 10 use const some amespaceConstA; 11 use const some amespaceConstB; 12 use const some amespaceConstC; 13 14 // PHP 7+ 之后版本可以使用一个 use 导入同一个 namespace 的类 15 use some amespace{ClassA, ClassB, ClassC as C}; 16 use function some amespace{fn_a, fn_b, fn_c}; 17 use const some amespace{ConstA, ConstB, ConstC}; 18 ?>
执行流程
use 关键字并不是立刻导入所 use 的类,它只是声明某类的完整类名(命名空间::类标示符),而后你在上下文中使用此类时系统才会根据 use 声明获取此类的完整类名 然后利用自动加载机制进行载入。
具体例子
1 <?php 2 use PsrHttpMessageServerRequestInterface as Request; 3 use PsrHttpMessageResponseInterface as Response; 4 require 'vendor/autoload.php'; 5 6 $app = new SlimApp; 7 $app->get('/hello/{name}', function (Request $request, Response $response) { 8 $name = $request->getAttribute('name'); 9 $response->getBody()->write("Hello, $name"); 10 return $response; 11 }); 12 $app->run();
就像如上的代码 自动载入函数是在 use 两个类之后方才实现的 因为 use 并不会立即使用此类 只有在你调用此类时系统才会在找不到此类的情况下通过 autoload 函数动态延迟加载,若仍加载不到,则报错。