PHP的自动加载机制
最近尝试着写一个简单的php框架,来加深对mvc的认识,其中类的载入是首先要解决的问题。这篇文章,让我们追根溯源,看看类的加载如何从最原始的做法然后一步一步改进,到现在形成比较成熟的做法。来对类的载入有一个更加深刻的认识。
1、面向过程式的做法
整个项目里到处都是include或require。
缺点:难看、不易维护
2、__autoload(魔术方法)
autoload机制可以使得PHP程序在使用类时才自动包含文件,而不是一开始就将所有的类文件全部包含,这就是自动加载。
当new一个类的时候,如果类不存在,则会调用此方法传入类名。
参考代码:
1 Tom.php 2 <?php 3 class Tom 4 { 5 public function say() 6 { 7 echo "Hello Tom." . PHP_EOL; 8 } 9 } 10 ?> 11 12 Lily.php 13 <?php 14 class Lily 15 { 16 public function say() 17 { 18 echo 'Hello Lily.' . PHP_EOL; 19 } 20 } 21 ?> 22 23 autoload.php 24 <?php 25 26 function __autoload($classname) 27 { 28 $filename = "./" . $classname . ".php"; 29 echo $classname . PHP_EOL; 30 include_once($filename); 31 } 32 33 $tom = new Tom(); 34 $lily = new Lily(); 35 echo $tom->say(); 36 echo $lily->say();
运行结果:
缺点:一个项目中仅能有一个这样的 __autoload() 函数,因为 PHP 不允许函数重名,也就是说你不能声明2个__autoload()函数文件,否则会报致命错误。php7.2已经弃用__autoload函数。
3、spl_autoload_register
1) spl_autoload_register是可以多次重复使用的,这一点正是解决了__autoload的短板。
2)注册的函数会进入队列中,多次注册时,先进先出,加载成功则终止,加载失败会继续调用队列中下一个被注册的函数。
参考代码1:
1 <?php 2 3 class MyClass { 4 public static function autoload($className) { 5 // ... 6 } 7 } 8 9 spl_autoload_register(array('MyClass', 'autoload')); 10 ?> 11 12 * Or you can use an instance : 13 <?php 14 class MyClass { 15 public function autoload($className) { 16 // ... 17 } 18 } 19 20 $instance = new MyClass(); 21 spl_autoload_register(array($instance, 'autoload')); 22 ?>
参考代码2:
1 Lily.php 2 <?php 3 4 class Lily 5 { 6 public function say() 7 { 8 echo 'Hello Lily.' . PHP_EOL; 9 } 10 } 11 ?> 12 <?php 13 /** 14 * spl_autoload_register($autoload_function, true, false) 15 * 第一个参数(autoload_function):欲注册的自动装载函数。 16 * 第二个参数(throw):此参数设置了 autoload_function 无法成功注册时, spl_autoload_register()是否抛出异常。 17 * 第三个参数(prepend):当为true时,spl_autoload_register()函数会添加函数到队列之首,而不是队列尾部。 18 */ 19 spl_autoload_register('autoload', true, true); 20 21 /** 22 * 自定义类加载 23 * @param string $className 24 */ 25 function autoload($className="") { 26 echo "类名为:autoload/".$className . PHP_EOL; 27 include "./{$className}.php"; 28 } 29 30 $Lily = new Lily(); 31 $Lily->say(); 32 33 //运行结果: 34 //类名为:autoload/Lily 35 //Hello Lily.
4、spl_autoload_register+namespace命名空间
自动加载现在是PHP现代框架的基石,基本都是spl_autoload_register来实现自动加载。namespace也是使用比较多的。所以spl_autoload_register + namespace 就成为了一个主流
参考代码:
1 Name.php 2 <?php 3 4 namespace Lib; 5 6 class Name 7 { 8 public static function test() 9 { 10 echo '123'; 11 } 12 } 13 ?> 14 loading.php 15 <?php 16 17 namespace autoload; 18 19 class loading 20 { 21 public static function autoload($className) 22 { 23 //根据PSR-O的第4点 把 转换层(目录风格符) DIRECTORY_SEPARATOR , 24 //便于兼容Linux文件找。Windows 下(/ 和 )是通用的 25 //由于namspace 很规格,所以直接很快就能找到 26 $fileName = str_replace('\', DIRECTORY_SEPARATOR, DIR . '\' . $className) . '.php'; 27 if (is_file($fileName)) { 28 require $fileName; 29 } else { 30 echo $fileName . ' is not exist'; 31 die; 32 } 33 } 34 } 35 ?> 36 index.php 37 <?php 38 39 //定义当前的目录绝对路径 40 define('DIR', dirname(__FILE__)); 41 //加载这个文件 42 require DIR . '/loading.php'; 43 //采用`命名空间`的方式注册。php 5.3 加入的 44 //也必须是得是static静态方法调用,然后就像加载namespace的方式调用,注意:不能使用use 45 spl_autoload_register("\autoload\loading::autoload"); 46 // 调用三个namespace类 47 //定位到Lib目录下的Name.php 48 LibName::test(); 49 50 //运行结果: 51 //123
下一篇文章,我们尝试利用 Composer 来一步一步构建自己的 PHP 框架。
参考链接:
https://www.zybuluo.com/phper/note/66447
https://www.php.net/manual/zh/function.spl-autoload-register.php