この記事では、主に PHP でクラスを自動ロードする方法を紹介します。これは、必要な友人に参考にしてもらえるように共有します。これは、私が PHP に出会ってからのことです。PHP には、PHP 独自のクラスの自動ロード方法、PHP のサードパーティの依存関係管理ツール Composer のロード方法、および PHP の自動ロード方法の 3 つの自動ロード方法があります。ヤフフレームワーク。このブログでは主に PHP5 に付属するロード方法について詳しく紹介します。composer と Yaf の下でのクラスの自動ロードについては、次回から 2 回に分けて学習していきます。
C や C++ などの言語の場合、PHP の別のファイルで関連するクラスやメソッドを使用する必要がある場合は、include、include_once、require または require_once を使用できます。ファイルはプロジェクトに含まれます。このうち、4つの違いは以下の通りです。
< ? php include("projname/home/lib/mylib/test/a.php"); include("projname/home/lib/mylib/test/b.php"); include("projname/home/lib/mylib/test/c.php"); ......
< ? php set_include_path("projname/home/lib/mylib/test"); include("a.php"); include("b.php"); include("c.php"); ......
get_include_path()函数只适用于获取当前的包含路径。
为了将双手从类的加载方式中解放出来,在PHP5及以后的版本中提供了一个自动加载的机制---autoload。Autoload可以使类在确实被需要的情况下才会被加载进来,也就是所谓的lazy loading,而不是一开始就include或者require所有的类文件。其中PHP提供的自动加载机制又分为两种---__autoload()以及spl_autoload_register()。
在PHP5中运行程序的过程中,如果发现某一个类并没有被包含进来,那么就会运行__autoload自动加载机制,将所需要的类加载进来。其写法如下:
< ? php public function __autoload($classname) { $fileName = $classname."php"; if (file_exist($fileName)) { require_once("$fileName"); } else { echo $fileName." doesn't exist!" } }
根据这个程序写法,我们可以得到如下的结论:保证自动加载机制的的原则就是要使得类名和文件名具有一种对应关系,类名+后缀构成了这个类所在的文件的名字。如果这个文件确实存在,那么就根据$fileName将该类加载进来。如果文件不存在,则提示用户,文件不存在。总的来说自动加载机制包括三个步骤:
根据类名确定文件名,也就是确定一种类名和文件名之间的统一对应规则;
根据文件名在磁盘上找到相应的对应文件(例子中是最简单的情况,就是类与调用他们的PHP文件都在同一个目录下);如果不在同一个目录下,那么可以使用set_include_path()指定要加载的路径;
将磁盘文件加载到文件系统中,这一步只是用一般的include和require包含相应的类文件;
__autoload()实现类的自动加载的原则就是:类名和文件名之间具有一种统一的对应关系,这是在一个系统中实现__autoload的关键所在。但是一个系统可能是有不同的人员所开发,如果在开发之前没有约定统一的标准,则可能存在不同的对应规则,导致需要在__autoload()中实现多种加载规则,那么可能导致__autoload()函数非常的臃肿。为了解决这个这个问题,PHP还提供了一个自动加载机制---spl_autoload_register().
SPL是Standard PHP Library(标准PHP库)的缩写,是PHP5引入的一个扩展库。SPL autoload是通过将函数指针autoload_func指向自动装载函数实现的。SPL具有两个不同的自动装载函数,分别是spl_autoload和spl_autoload_call,通过将autoload_fun指向这两个不同的加载函数地址可以实现不同的自动加载机制。
spl_autoload
spl_autoload是SPL实现的默认的自动加载函数,是一个可以接受两个参数的函数。其中第一个函数为$class_name,表示要加载的类名;第二个参数是$file_extension为可选参数,表示类文件的扩展名。$file_extension中可以指定多个扩展名,扩展名之间用分号隔开即可,不指定扩展名,则使用默认的扩展名.inc或者.php。spl_autoload首先将$class_name变为小写,然后在所有的include_path中搜索$ class_name.inc或者$class_name.php文件。如果找到对应的文件,就加载对应的类。其实可以手动的使用spl_autoload("xxxx",".php")来实现xxxx类的加载。这其实和require/include差不多,但是,spl_autoload相对来说灵活一点,因为可以指定多个扩展名。
前面说到,spl_autoload_register中包含的函数指针autoload_func用于指定要使用的加载函数。那么,我们必须将对应的函数地址赋值给autoload_func,spl_autoload_register()正实现了给函数指针autoload_func赋值的功能。如果spl_autoload_register()函数中不含有任何的参数,则默认是将spl_autoload()赋值给autoload_func.
spl_autoload_call
SPL模块的内部其实还存在着一个autoload_functions,其本质上是一个哈希表,或者为了直观的理解,我们将其想像成一个容器,里面的各个元素都是指向加载函数的指针。spl_autoload_call的实现机制其实也比较简单,按照一定的顺序遍历这个容器,执行里面的函数指针指向的加载函数,每执行一个指针之后都会检查所需要的类是否已经完成加载。如果完成了加载,则退出。否则继续接着向下执行。如果执行完所有的加载函数之后,所需要的类仍然没有完成加载,则spl_autoload_call()直接退出。这也就是说即使使用了autoload机制,也不一定能够完成类的加载,其关键在于看你如何创建你的自动加载函数。
既然,存在一个autoload_functions,那么如何将创建的自动加载函数添加到其中呢?spl_autoload一样,同样使用spl_autoload_register()将加载函数注册到autoload_functions中。当然可以通过spl_autoload_unregister()函数将已经注册的函数从autoload_functions从哈希表中删除。
这里需要说明的一点是spl_autoload_register实现自动加载的顺序。spl_autoload的自动加载顺序为:首先判断autoload_func是否为空,如果autoload_func为空,则查看是否定义了__autoload函数,如果没有定义,则返回,并报错;如果定义了__autoload()函数,则返回加载的结果。如果autoload_func不为空,直接执行autoload_func指针指向的函数,不会检查__autoload是否定义。也就是说优先使用spl_autoload_register()注册过的函数。
根据以上介绍,如果autoload_func为非空是就不能自动执行__autoload()函数了。如果想在使用spl_autoload_register()函数的情况下,依然可以使用__autoload()函数,则可以将__autoload函数通过spl_autoload_register()添加到哈希表中,即,spl_autoload_register(__autoload())。下面的代码示例分别说明了如何注册普通的方法和类的静态公有方法。
普通函数的注册方法。
<? php /** * @ 普通函数的调用方法,可以调用后缀名分别为.php和.class.php的类文件 */ function loadFielEndOfPhp($classname) { $fileName = $classname.".php"; if (file_exist($fileName)) { require_once("$fileName"); } else { echo $fileName." doesn't exist!" } } function loadFielEndOfClassPhp($classname) { $fileName = $classname.".class.php"; if (file_exist($fileName)) { require_once("$fileName"); } else { echo $fileName." doesn't exist!" } spl_autoload_register("loadFielEndOfPhp"); spl_autoload_register("loadFielEndOfClassPhp"); }
类中静态的加载函数的注册方法。
<? php /** * @ 类中静态成员函数的调用方法,可调用后缀名为.php和.class.php的文件 */ class test { public static function loadFielEndOfPhp($classname) { $fileName = $classname.".php"; if (file_exist($fileName)) { require_once("$fileName"); } else { echo $fileName." doesn't exist!" } } public static function loadFielEndOfClassPhp($classname) { $fileName = $classname.".class.php"; if (file_exist($fileName)) { require_once("$fileName"); } else { echo $fileName." doesn't exist!" } } spl_autoload_register(array("test","loadFielEndOfPhp")); //spl_autoload_register("test::loadFielEndOfPhp"); //上一行的另一种写法,不是使用数组的形式完成注册; spl_autoload_register(array("test","loadFielEndOfClassPhp")); //spl_autoload_register("test::loadFielEndOfClassPhp"); //第三行的另一种写法,不是使用数组的形式完成注册; }
相关推荐:
PHPにおけるクラスの静的呼び出しとスコープ解決演算子の違い
以上がPHP でクラスを自動的にロードする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。