- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章PHP中的自动加载操作实现方法详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本文实例讲述了PHP中的自动加载操作实现方法。分享给大家供大家参考,具体如下:
what is 自动加载?
或许你已经对自动加载有所了解。简单描述一下:自动加载就是我们在new一个class的时候,不需要手动去写require来导入这个class.php文件,程序自动帮我们加载导入进来。这是php5.1.2(好像是)版本新加入一个功能,他解放了程序员的双手,不需要手动写那么多的require,变得有那么点智能的感觉.
自动加载可以说是现代PHP框架的根基,任何牛逼的框架或者架构都会用到它,它发明出来的理由是啥呢?一个字:懒。因为项目越来愈大,相关联的类库文件越来越多,我们不可能再像小项目那样在一个文件中全部手动一个一个require.
如何才能自动加载呢? PHP 5.2版本更新了自动加载需要的一个魔术方法——__autoload($class_name) 。
正是这个神奇的内置魔术函数,才能让我们这些屌丝偷懒。我们来看下这个如何使用它.
1. 自动加载的原理以及__autoload的使用 。
自动加载的原理,就是在我们new一个class的时候,PHP系统如果找不到你这个类,就会去自动调用本文件中的__autoload($class_name)方法,我们new的这个class_name 就成为这个方法的参数。所以我们就可以在这个方法中根据我们需要new class_name的各种判断和划分就去require对应的路径类文件,从而实现自动加载.
我们先一步步来,看下__autoload()的自动调用,看个例子:
index.php 。
1
|
$db
=
new
DB();
|
如果我们不手动导入DB类,程序可能会报错,说找不到这个类:
Fatal error: Class 'DB' not found in D:\wamp\www\testphp\autoload\index.php on line 3 。
那么,我们现在加入__autoload()这个方法再看看:
1
2
3
4
5
6
|
$db
=
new
DB();
function
__autoload(
$className
)
{
echo
$className
;
exit
();
}
|
根据上面自动加载机制的描述,你分析下会输出什么? 没错:肯定是输出:DB, 也就是我们需要new 的类的类名。所以,这个时候我们就可以在__autoload()方法里,根据需要去加载类库文件了.
index.php 。
1
2
3
4
5
|
$db
=
new
DB();
function
__autoload(
$className
)
{
require
$className
.
'.php'
;
}
|
DB.php 。
1
2
3
4
5
6
7
|
class
DB
{
publicfunction __construct()
{
echo
'Hello DB'
;
}
}
|
这样子我们就很轻松的将我们需要new 的class 全部导入了进来,这样子,我们就可以轻松的new N个class,比如:
1
2
3
4
5
6
7
8
9
10
11
|
<?php
function
__autoload(
$className
)
{
require
$className
.
'.php'
;
}
$db
=
new
DB();
$info
=newInfo();
$gender
=newGender();
$name
=newName();
//也是支持静态方法直接调用的
Height::test();
|
2. spl_autoload_register的使用 。
小的项目,用__autoload()就能实现基本的自动加载了。但是如果一个项目过大,或者需要不同的自动加载来加载不同路径的文件,这个时候__autoload就悲剧了,原因是一个项目中仅能有一个这样的 __autoload() 函数,因为 PHP 不允许函数重名,也就是说你不能声明2个__autoload()函数文件,否则会报致命错误,我了个大擦,那怎么办呢?放心,你想到的,PHP开发大神早已经想到.
所以spl_autoload_register()这样又一个牛逼函数诞生了,并且取而代之它。它执行效率更高,更灵活 。
先看下它如何使用吧:
当我们去new一个找不到的class时,PHP就会去自动调用sql_autoload_resister注册的函数,这个函数通过它的参数传进去:
1
2
3
4
5
6
7
8
9
10
|
sql_autoload_resister(
$param
) 这个参数可以有多种形式:
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'
;
}
});
|
index.php 。
1
2
3
4
5
6
7
|
function
load1(
$className
)
{
echo
1;
require
$className
.
'.php'
;
}
spl_autoload_register(
'load1'
);
//将load1函数注册到自动加载队列中。
$db
=
new
DB();
//找不到DB类,就会自动去调用刚注册的load1函数了
|
上面就是实现了自动加载的方式,我们同样也可以用类加载的方式调用,但是必须是static方法:
1
2
3
4
5
6
7
8
9
10
11
|
class
autoloading {
//必须是静态方法,不然报错
public
static
function
load(
$className
)
{
require
$className
.
'.php'
;
}
}
//2种方法都可以
spl_autoload_register(
array
(
'autoloading'
,
'load'
));
spl_autoload_register(
'autoloading::load'
);
$db
=
new
DB();
//会自动找到
|
需要注意的是,如果你同时使用spl_autoload_register和__autoload,__autoload会失效!!! 再说了,本来就是替换它的,就一心使用spl_autoload_register就好了.
3. 多个spl_autoload_register的使用 。
spl_autoload_register是可以多次重复使用的,这一点正是解决了__autoload的短板,那么如果一个页面有多个,执行顺序是按照注册的顺序,一个一个往下找,如果找到了就停止.
我们来看下这个例子,DB.php就在本目录下,Info.php在/lib/目录下.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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'
);
$db
=
new
DB();
//DB就在本目录下
$info
=newInfo();
//Info 在/lib/Info.php
|
我们注册了3个自动加载函数。执行结果是啥呢?
1Hello DB 123Hello Info 。
我们分析下:
new DB的时候,就按照注册顺序,先去找load1()函数了,发现找到了,就停止了,所以输出1 Hello Word 。
new Info的时候,先是安装注册顺序,先找load1(), 所以输出了1,发现没找到,就去load2()里面去找,所以输出了2,还是没这个文件,就去__autoload()函数里找,所以,先输出了3,再输出Hello Info 。
注意,前面说过,spl_autoload_register使用时,__autoload会无效,有时候,我们希望它继续有效,就可以也将它注册进来,就可以继续使用.
我们可以打印spl_autoload_functions()函数,来显示一共注册了多少个自动加载:
1
2
3
4
5
6
|
var_dump(spl_autoload_functions());
//数组的形式输出
array
(size=3)
0 => string
'load1'
(length=5)
1 => string
'load2'
(length=5)
2 => string
'__autoload'
(length=10)
|
4. spl_autoload_register自动加载+namespace命名空间 的使用 。
前面已经说过,自动加载现在是PHP现代框架的基石,基本都是spl_autoload_register来实现自动加载。namespace也是使用比较多的。所以spl_autoload_register + namespace 就成为了一个主流。根据PSR-0的规范,namespace命名已经非常规范化,所以用namespace就能找到详细的路径,从而找到类文件.
我们举例子来看下:
AutoLoading\loading 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?php
namespaceAutoLoading;
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
;
}
}
}
|
上面就是一个自动加载的核心思想方法。下面我们就来spl_autoload_register来注册这个函数:
index.php 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?php
//定义当前的目录绝对路径
define(
'DIR'
, dirname(
__FILE__
));
//加载这个文件
require
DIR .
'/loading.php'
;
//采用`命名空间`的方式注册。php 5.3 加入的
//也必须是得是static静态方法调用,然后就像加载namespace的方式调用,注意:不能使用use
spl_autoload_register(
"\\AutoLoading\\loading::autoload"
);
// 调用三个namespace类
//定位到Lib目录下的Name.php
Lib\Name::test();
//定位到App目录下Android目录下的Name.php
App\Android\Name::test();
//定位到App目录下Ios目录下的Name.php
App\Ios\Name::test();
|
由于我们是采用PSR-O方式来定义namespace的命名的,所以很好的定位到这个文件的在哪个目录下了。很爽。对不对.
APP\Android\Name 。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php
namespaceApp\Android;
className
{
public
function
__construct()
{
echo
__NAMESPACE__ .
"<br>"
;
}
public
static
function
test()
{
echo
__NAMESPACE__ .
' static function test <br>'
;
}
}
|
所以就会很容易找到文件,并输出:
Lib static function test App\Android static function test App\Ios static function test 。
好了。基本自动加载的东西就讲完了。很实用的东西.
4. 同命名空间下的相互调用 。
在平时我们使用命令空间时,有时候可能是在同一个命名空间下的2个类文件在相互调用。这个时候就要注意,在自动调用的问题了.
比如Lib\Factory.php 和 Lib\Db\MySQL.php 。
我想在 Lib\Factory.php 中调用 Lib\Db\MySQL.php。怎么调用呢?以下是错误的示范:
1
2
|
newLib\Db\MySQL();
//报错,提示说 D:\wamp\www\testphp\module\Lib\Lib\Db\MySQL.php is not exist
|
看到没?这种方式是在Lib\命名空间的基础上来加载的。所以会加载2个Lib。这种方式相当于相对路径在加载.
正确的做法是,如果是在同一个命名空间下平级的2个文件。可以直接调用,不用命名空间.
1
2
|
newMySQL();
//直接这样就可以了。
newDb\MySQL();
//如果有个Db文件夹,就这样。
|
还有一种方法就是使用 use 。使用user就可以带上Lib了。use使用的是绝对路径.
1
2
|
useLib\Db\MySQL;
newMySQL();
|
我想在 Lib\Db\MySQL.php 中调用 Lib\Register.php。怎么调用呢?
应该这样 。
1
2
|
useLib\Register;
Register::getInstance();
|
因为现在已经在Lib\Db这样一个命名空间了,如果你不用use,而是使用Lib\Register::getInstance()或者使用Register::getInstance()的话。将是在Lib\Db这个空间下进行相对路径的加载,是错误的.
希望本文所述对大家PHP程序设计有所帮助.
原文链接:https://www.zybuluo.com/phper/note/66447 。
最后此篇关于PHP中的自动加载操作实现方法详解的文章就讲到这里了,如果你想了解更多关于PHP中的自动加载操作实现方法详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!