spl_autoload

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

spl_autoload__autoload() 的默认实现

说明

spl_autoload(string $class, ?string $file_extensions = null): void

此函数旨在用作 __autoload() 的默认实现。如果没有其他指定,并且 spl_autoload_register() 在没有参数的情况下被调用,则 spl_autoload() 将用于之后对 __autoload() 的任何调用。

参数

class

要实例化的类的名称(以及命名空间)。

file_extensions

默认情况下,它会检查所有 include_path 以包含由小写类名附加文件名扩展名 .inc.php 构成的文件名。

返回值

不返回任何值。

错误/异常

当类未找到且没有其他自动加载器注册时,抛出 LogicException

变更日志

版本 说明
8.0.0 file_extensions 现在可以为 null。

添加备注

用户贡献笔记 9 notes

93
simast at gmail dot com
15 年前
注意,默认的自动加载实现是用 C 编写的,始终比您的原生 PHP 实现略快。

这里有一个技巧,可以将默认实现与任何配置一起使用

<?php

// 您的自定义类目录
define('CLASS_DIR', 'class/')

// 将您的类目录添加到 include 路径
set_include_path(get_include_path().PATH_SEPARATOR.CLASS_DIR);

// 您可以使用此技巧使自动加载器查找常用的“My.class.php”类型文件名
spl_autoload_extensions('.class.php');

// 使用默认的自动加载实现
spl_autoload_register();
?>

这在开箱即用时也适用于命名空间。因此,您可以编写类似“use My\Name\Object”的代码,它将映射到“class/My/Name/Object.class.php”文件路径!
3
theking2 at king dot ma
2 年前
命名空间和类名都区分大小写。这可能会导致自动加载在区分大小写的操作系统/文件系统中出现问题。

考虑以下代码
<?php declare(strict_types=1);
set_include_path(get_include_path() . PATH_SEPARATOR . 'class/');
spl_autoload_extensions('.class.php');
spl_autoload_register();

$foobar = new \foo\bar();
?>

以及一个类文件 /class/foo/bar.class.php
<?php declare(strict_types=1);
namespace
Foo;

class
Bar {
public function
__construct() {
echo
'Map constructed';
}
}
?>

无论操作系统/文件系统是否区分大小写,这都可以正常工作。

名为 ./class/Foo/Bar.class.php 的文件只有在不区分大小写的环境下才能找到,因为默认的类加载器会将类名转换为小写以查找类文件名。

顺便说一句,类文件的此内容将等同于上面的内容
<?php declare(strict_types=1);
namespace
foo;

class
bar {
public function
__construct() {
echo
'Map constructed';
}
}
?>

类 /foo/bar 和 /Foo/Bar 是同一个东西。
11
EVODelavega
10 年前
我只是想对 simast at gmail dot com 的笔记做出反应:虽然他说 C 的性能优于 PHP,但他提出的建议是微优化。我并不完全反对微优化代码,但如果你要这样做,就彻底做。

<?php

// 您的自定义类目录
define('CLASS_DIR', 'class/')

// 将您的类目录添加到 include 路径
set_include_path(get_include_path().PATH_SEPARATOR.CLASS_DIR);

这会将 include 路径添加到 PHP 将扫描类文件的路径的末尾,导致在实际查找 CLASS_DIR 之前出现大量失败(文件未找到)。因此,更明智的做法是编写

set_include_path(
CLASS_DIR.
PATH_SEPARATOR,
get_include_path()
);
11
Luke Scott
13 年前
如果您想在使用 APC 缓存的情况下充分利用自动加载,请不要使用 spl_autoload。它使用相对路径,因此即使使用 apc.stat=0 也会执行 stat(或者根本不起作用)。

相反,创建一个自定义函数并使用绝对路径的 require/include(使用 spl_autoload_register 注册它)。

不要使用 *_once 函数或相对路径。这将比 spl_autoload 更难失败。

还要避免使用 file_exists 和 is_file。这也会执行 stat。

为什么 stat 不好?因为它们访问文件系统。PHP 确实有一个 stat 缓存来帮助,但这会破坏 apc.stat = 0 的目的。

同样需要记住,保持自定义自动加载函数简单是个好主意。这是我的 Loader 类

<?php

class Loader
{
public static function
registerAutoload()
{
return
spl_autoload_register(array(__CLASS__, 'includeClass'));
}

public static function
unregisterAutoload()
{
return
spl_autoload_unregister(array(__CLASS__, 'includeClass'));
}

public static function
includeClass($class)
{
require(
PATH . '/' . strtr($class, '_\\', '//') . '.php');
}
}

?>

还想指出,APC 对全局范围内执行的 require/include(不是 *_once)进行了优化,即使使用相对路径(并且不带条件)。因此,最好明确包含您知道每个请求都会使用的文件(但不要使用 *_once)。例如,您可以将“registerProfiledAutoload”添加到上面的类,并跟踪您正在包含的内容,以帮助您确定哪些文件可以明确包含(在开发期间,而不是生产期间)。关键是尽量不要过度使用自动加载。

如果您必须使用相对路径,并且不关心必须将文件名转换为小写,那么 spl_autoload 非常适合。
17
daniel
14 年前
请注意,此函数会将要查找的类名转换为小写,如果找不到 Foo_Bar.php,请不要感到困惑。

此外,与大多数其他自动加载代码片段不同,此函数不会将下划线转换为斜杠。

class Foo_Bar {}
将加载 foo_bar.php,而不会尝试加载 foo/bar.php。

您可以通过以下方法解决此问题:
spl_autoload_register(function($class) { return spl_autoload(str_replace('_', '/', $class));});
8
Philip
10 年前
文档在提到“正在实例化的类的(以及命名空间的)小写名称”时有点不清楚。

实际上,这意味着参数可以是任何大小写,但在 PHP 开始查找文件之前,它将被转换为小写。这可能是因为在 PHP 中,类名不区分大小写(以及函数名和命名空间),因此它需要转换为某种规范格式。
13
safak_ozpinar at NOSPAM dot yahoo dot com
16 年前
请注意,文件扩展名的顺序对性能至关重要。您应该将您喜欢的文件扩展名的优先级设置最高,或者只为您的类文件使用一个扩展名。请查看以下示例

一些类文件

ClassA.php
<?php class ClassA { var $val = 'Hello from class "ClassA"'; } ?>
ClassB.php
<?php class ClassB { var $val = 'Hello from class "ClassB"'; } ?>
ClassC.php
<?php class ClassC { var $val = 'Hello from class "ClassC"'; } ?>
ClassD.php
<?php class ClassD { var $val = 'Hello from class "ClassD"'; } ?>
ClassE.php
<?php class ClassE { var $val = 'Hello from class "ClassE"'; } ?>

1. 简单
<?php
// 默认优先级:.inc .php
for($n=65; $n<70; $n++) {
$className = 'Class'.chr($n);
spl_autoload($className);
$ins = new $className;
echo
$ins->val.'<br>';
}
// 4.2 毫秒
?>

2. 更改优先级
<?php
spl_autoload_extensions
('.php,.inc');
// 新优先级:.php .inc
for($n=65; $n<70; $n++) {
$className = 'Class'.chr($n);
spl_autoload($className);
$ins = new $className;
echo
$ins->val.'<br>';
}
// 1.4 毫秒
?>

或者,您可以使用此简单的函数,它对于优先级较低的扩展来说运行速度更快 :)
<?php
function my_autoload($className, $extList='.inc,.php') {
$ext = explode(',',$extList);
foreach(
$ext as $x) {
$fname = $className.$x;
if(@
file_exists($fname)) {
require_once(
$fname);
return
true;
}
}
return
false;
}

for(
$n=65; $n<70; $n++) {
$className = 'Class'.chr($n);
my_autoload($className);
$ins = new $className;
echo
$ins->val.'<br>';
}
// 2.6 毫秒
?>
---
Safak Ozpinar - 伊斯坦布尔大学,计算机工程
14
Ivan Stojmenovic
12 年前
一个简单的示例,展示了如何在您的 MVC、Framewrk 的应用程序中使用 spl_autoload 函数。例如,将使用 Loader 类。


<?php

class Loader
{

/**
* 控制器目录路径
*
* @var Array
* @access protected
*/
protected $_controllerDirectoryPath = array();

/**
* 模型目录路径
*
* @var Array
* @access protected
*/
protected $_modelDirectoryPath = array();

/**
* 库目录路径
*
* @var Array
* @access protected
*/
protected $_libraryDirectoryPath = array();


/**
* 构造函数
* 常量包含模型、视图、控制器和库的完整路径
* 目录。
*
* @Constant MPATH,VPATH,CPATH,LPATH
*/

public function __construct()
{
$this->modelDirectoryPath = MPATH;
$this->viewDirectoryPath = VPATH;
$this->controllerDirectoryPath = CPATH;
$this->libraryDirectoryPath = LPATH;

spl_autoload_register(array($this,'load_controller'));
spl_autoload_register(array($this,'load_model'));
spl_autoload_register(array($this,'load_library'));

log_message('debug',"Loader Class Initialized");
}

/**
*-----------------------------------------------------
* 加载库
*-----------------------------------------------------
* 加载库的方法。
* 此方法返回类对象。
*
* @library String
* @param String
* @access public
*/
public function load_library($library, $param = null)
{
if (
is_string($library)) {
return
$this->initialize_class($library);
}
if (
is_array($library)) {
foreach (
$library as $key) {
return
$this->initialize_class($library);
}
}
}

/**
*-----------------------------------------------------
* 初始化类
*-----------------------------------------------------
* 初始化类的方法
* 此方法返回新对象。
* 此方法可以使用 (array) 初始化更多类
*
* @library String|Array
* @param String
* @access public
*/
public function initialize_class($library)
{
try {
if (
is_array($library)) {
foreach(
$library as $class) {
$arrayObject = new $class;
}
return
$this;
}
if (
is_string($library)) {
$stringObject = new $library;
}else {
throw new
ISException('类名必须是字符串。');
}
if (
null == $library) {
throw new
ISException('您必须输入类的名称。');
}
} catch(
Exception $exception) {
echo
$exception;
}
}

/**
* 自动加载控制器类
*
* @param string $class
* @return object
*/

public function load_controller($controller)
{
if (
$controller) {
set_include_path($this->controllerDirectoryPath);
spl_autoload_extensions('.php');
spl_autoload($class);
}
}


/**
* 自动加载模型类
*
* @param string $class
* @return object
*/

public function load_models($model)
{
if (
$model) {
set_include_path($this->modelDirectoryPath);
spl_autoload_extensions('.php');
spl_autoload($class);
}
}

/**
* 自动加载库类
*
* @param string $class
* @return object
*/

public function load_library($library)
{
if (
$library) {
set_include_path($this->libraryDirectoryPath);
spl_autoload_extensions('.php');
spl_autoload($class);
}
}



}

?>
7
contato at felipebarth dot com dot br
11 years ago
<?php
/*
* 定义用于加载类的函数,
* 替换旧的 __autoload。
* ROOT 是系统路径根目录的常量
*/
spl_autoload_extensions('.class.php');
spl_autoload_register('loadClasses');

function
loadClasses($className)
{

if(
file_exists(ROOT_DIR.DS.'controller/'.$className.'.class.php' ) ){
set_include_path(ROOT_DIR.DS.'controller'.DS);
spl_autoload($className);
}
elseif(
file_exists('model/'.$className.'.class.php' ) ){
set_include_path(ROOT_DIR.DS.'model'.DS);
spl_autoload($className);
}elseif(
file_exists('view/'.$className.'.class.php' ) ){
set_include_path(ROOT_DIR.DS.'view'.DS);
spl_autoload($className );
}else
{
set_include_path(ROOT_DIR.DS.'lib'.DS);
spl_autoload($className );
}
}
?>
To Top