这篇文章将从初学者到进阶同学的角度,循序渐进的谈论一下 PHP 中的自动加载类,以及深入理解 spl_autoload , __autoload ,spl_autoload_register。
什么是加载
学过java 或者c的同学都知道,要在一个文件中使用另一个文件所定义的类,java是通过import
实现的,而c是通过include 头文件实现的,相对来说都简单,同样,在PHP中也有类似这样的机制,你也可以在前面使用include
或者include_once
等等的手段来加载其他类的文件。
除此以外,PHP还有一个自动加载类机制,如果说PHP找不到类的定义(比如说你在A.class.php 中想要new 一个B 类),就会触发自动加载类。
自动加载类之 __autoload
直接上例子
本例尝试分别从 MyClass1.php 和 MyClass2.php 文件中加载 MyClass1 和 MyClass2 类。
<?php
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
直接拿来用
在实际开发中,如果我们要使用自动加载类,通常代码是这样
<?php
//Define autoloader
function __autoload($className) {
if (file_exists($className . '.php')) {
require_once $className . '.php';
return true;
}
return false;
}
function canClassBeAutloaded($className) {
return class_exists($className);
}
?>
面试题:如果非要说上面的代码有地方可以改进,你说说是哪里?
没有必要使用require_once 或者是 include_once,因为只有在类找不到的时候才会出发自动加载类。
再进一步
在英文的api中我们发现有这样一句话,
Whilst the __autoload() function can also be used for autoloading classes and interfaces, its preferred to use the spl_autoload_register() function. This is because it is a more flexible alternative (enabling for any number of autoloaders to be specified in the application, such as in third party libraries). For this reason, using __autoload() is discouraged and it may be deprecated in the future.
官方文档中更建议使用spl_autoload_register
,因为更加灵活,可以保证任意数量的自动加载类在项目中顺利运行,尤其是在使用第三方库。
这个说的并不是很明确,我再解释一下。
谈谈spl_autoload_register()
spl_autoload_register()
允许你注册多个方法,或者静态方法,PHP引擎会把他们放到栈/队列中,当你“new” 一个类的时候,会顺序的调用。
举个例子
spl_autoload_register('myAutoloader');
function myAutoloader($className)
{
$path = '/path/to/class';
include $path.$className.'.php';
}
//-------------------------------------
$myClass = new MyClass();
对于对于myAutoloader 来说,Myclass,就是一个字符串,所以说你可以对它为所欲为,比如说加后缀,有人喜欢.php,有人喜欢.class.php,你只要注册了自动加载类的方法,引擎就会自动调用,不用你在文件开头进行include声明。
用spl_autoload_register 的好处呢?
用spl_autoload_register 之后,你不需要在每一个类中都去重写__autoload方法,并且你可以注册多次
举个例子
spl_autoload_register('MyAutoloader::ClassLoader');
spl_autoload_register('MyAutoloader::LibraryLoader');
spl_autoload_register('MyAutoloader::HelperLoader');
spl_autoload_register('MyAutoloader::DatabaseLoader');
class MyAutoloader
{
public static function ClassLoader($className)
{
//your loading logic here
}
public static function LibraryLoader($className)
{
//your loading logic here
}
对于spl_autoload,简单来说就是__autoload 的默认实现,如果spl_autoload_register()在无参的情况下被调用,就会调用__autoload()。
补充几点,如果说你的所有的文件都放在同一个文件夹内,不仅仅是.php结尾的还有.inc结尾的用户配置文件,可以使用set_include_path()把所有需要的文件防盗php的include路径下,再通过spl_autoload_extensions()列出扩展,例子:
set_include_path(get_include_path().PATH_SEPARATOR.'path/to/my/directory/');
spl_autoload_extensions('.php, .inc');
spl_autoload_register();