网站首页 > 基础教程 正文
1. 什么是自动加载?
自动加载就是在实例化类的时候,PHP自动帮我们把需要用到的文件给require进来,不需要我们手动一个一个去require;
自动加载可以说是现代PHP框架的核心基础,就像地基一样,像Laravel,thinkphp,yii2等框架都是基于自动加载实现的文件自动载入。
2. 如何实现?
1. __autoload()方法实现自动加载
index.php
<?php
function __autoload($classname){
require $className . '.php';
}
$test = new Test();//在index.php同级目录下加载Test.php文件
小项目这样做当然没问题,但是项目变大了之后就无法满足需求了,比如需要加载多个不同目录的文件__autoload就无法实现了,因为一个项目只能有一个__autoload,不能申明多个。那怎么解决呢?就是下面的spl_autoload_register了。
2. spl_autoload_register方法实现自动加载
spl_autoload_register就是设计用来取代__autoload的,可以多次调用注册,使用方法如下:
<?php
//多种形式
sql_autoload_resister('load_function'); //函数名
sql_autoload_resister(array('load_object', 'load_function')); //类和静态方法
sql_autoload_resister('load_object::load_function'); //类和方法的静态调用
//php 5.3之后,也可以像这样支持匿名函数了。
spl_autoload_register(function($className){
if (is_file('./lib/' . $className . '.php')) {
require './lib/' . $className . '.php';
}
});
需要注意的是,当项目中同时存在spl_autoload_register和__autoload时,__autoload会失效,想要同时工作,只能把__autoload作为函数注册到spl_autoload_register中。
多个spl_autoload_register注册后,调用的顺序是按照注册的顺序执行,直到找到可以加载的文件为止。
function load1($className)
{
echo 1;
if (is_file($className . '.php')) {
require $className . '.php';
}
}
function load2($className)
{
echo 2;
if (is_file('./app/' . $className . '.php')) {
require './app/' . $className . '.php';
}
}
function __autoload($className)
{
echo 3;
if (is_file('./lib/' . $className . '.php')) {
require './lib/' . $className . '.php';
}
}
//注册了3个
spl_autoload_register('load1');
spl_autoload_register('load2');
spl_autoload_register('__autoload');
$config= new Config(); //Config就在本目录下
$test= new Test(); //Test在/app/Test.php
//打印结果
//1Hello DB
//123Hello Info
当我们想知道项目中注册了多少自动加载函数的时候,可以使用spl_autoload_functions函数
var_dump(spl_autoload_functions());
//数组的形式输出
array (size=3)
0 => string 'load1' (length=5)
1 => string 'load2' (length=5)
2 => string '__autoload' (length=10)
3. spl_autoload_register+namespace实现文件规范化自动加载
根据PSR-0规范,namespace的命名就可以很方便的直接找到对应文件,而自动加载方法的类名是包含namespace的名称的,因此可以直接加载
index.php
<?php
//定义当前的目录绝对路径
define('DIR', dirname(__FILE__));
//加载这个文件
require DIR . './Loading.php';
//采用`命名空间`的方式注册。php 5.3 加入的
//也必须是得是static静态方法调用,然后就像加载namespace的方式调用,注意:不能使用use
spl_autoload_register("\\App\\Loading::autoload");//Loading文件使用了namespace这里也就只能使用全路径调用
// 调用三个namespace类
//定位到Lib目录下的Name.php
use Lib\Name;
Name::test();
//定位到App目录下Android目录下的Name.php
Android\Name::test();
//定位到App目录下Ios目录下的Name.php
\Ios\Name::test();
Loading.php
<?php
namespace App;
class Loading
{
public static function autoload($className)
{
//根据PSR-O的第4点 把 \ 转换层(目录风格符) DIRECTORY_SEPARATOR ,
//便于兼容Linux文件找。Windows 下(/ 和 \)是通用的
//由于namspace 很规格,所以直接很快就能找到
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, DIR . '\\' . $className) . '.php';
if (is_file($fileName)) {
require $fileName;
} else {
echo $fileName . ' is not exist';
die;
}
}
}
Android/Name.php
<?php
namespace Android;
class Name{
public static function test(){
echo __NAMESPACE__.' name'.PHP_EOL;
}
}
Ios/Name.php
<?php
namespace Ios;
class Name{
public static function test(){
echo __NAMESPACE__.' name'.PHP_EOL;
}
}
Lib/Name.php
<?php
namespace Lib;
class Name{
public static function test(){
echo __NAMESPACE__.' name'.PHP_EOL;
}
}
输出:
Lib name
Android name
Ios name
4. 同根命名空间下的相互调用
在同一命名空间下相互调用可能会存在意想不到的问题,假如在Lib/Name.php想调用Lib/Driver/Config.php
new Lib\Driver\Config();
//报错C:\Users\53101\Desktop\study\php\autoload_study\Lib\Lib\Driver\Config.php is not exist
这种命名空间的调用实际上是一个相对路径,当前已经在Lib命名空间下了,所以不需要再重复调用Lib命名空间,正确的做法是:
//同级别调用
new Config();
//下一级别目录调用
new Driver\Config();
//或者使用use关键字,use引入的namespace是绝对路径
use Lib\Driver\Config;
new Config();
//也可以直接写绝对路径命名空间调用
new \Lib\Driver\Config();//在Lib前加\即调用绝对路径
如果反过来在Lib/Driver/Config.php中想调用Lib/Name.php就只能使用绝对路径引用的方式,因为相对路径已经到了下级目录Lib/Driver,无法找到上级目录Lib的文件。
//use绝对路径
use Lib\Name;
Name::test();
//直接绝对路径调用
\Lib\Name::test();
总结:
实现自动加载有两种方式
- __autolaod函数
- spl_autoload_register函数注册
实际使用时是配合namespace使用的,因为PSR-0规范可以方便地找到需要加载的文件,命名空间在调用时实际上就已经把路径写出来了,只需要把对应class加载进来就可以了。
同根命名空间下相互调用要注意可能出现的问题。实际使用时尽量使用use关键字加载,或者绝对路径加载
- 上一篇: PHP安全编码规范不可忽略
- 下一篇: php 多进程是如何实现的?
猜你喜欢
- 2024-11-23 西邮冯景瑜团队挖掘到CVE漏洞,被国家信息安全漏洞库收录公布
- 2024-11-23 PHP操作SQL数据库增删改查的代码
- 2024-11-23 简单轻量级的php的web防火墙,拦截SQL注入和XSS攻击
- 2024-11-23 PHP操作FTP类实现(上传、下载、移动、创建)的方法
- 2024-11-23 PHP7开发API离不开签名验证,你是如何设计?
- 2024-11-23 PHP连接msSQL数据库方法
- 2024-11-23 「PHP」如何使用imap协议接收邮件
- 2024-11-23 php 多进程是如何实现的?
- 2024-11-23 PHP安全编码规范不可忽略
- 2024-11-23 PHP使用json_encode()处理数组时,不转义 中文和 反斜线 等字符串
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)