PHP Conference Japan 2024

spl_autoload

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

spl_autoload__autoload() 的預設實作

說明

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

此函式旨在作為 __autoload() 的預設實作。如果沒有其他指定,且在沒有任何參數的情況下呼叫 spl_autoload_register(),則 spl_autoload() 將用於任何後續對 __autoload() 的呼叫。

參數

class

正在實例化的類別名稱。呼叫函式時,帶有命名空間的類別名稱會傳遞給此參數。 class 參數將不包含完整限定識別符號的前導反斜線。

file_extensions

預設情況下,它會檢查所有 include_path 中是否包含由小寫類別名稱加上檔案副檔名 .inc.php 所組成的檔案名稱。

返回值

不返回任何值。

錯誤/異常

如果找不到類別且沒有其他已註冊的自動載入器,則會拋出 LogicException

更新日誌

版本 說明
8.0.0 file_extensions 現在可以為 null。

新增註釋

使用者貢獻的註釋 9 則註釋

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" 檔案路徑!
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 的檔案只會在不區分大小寫的情況下被找到,因為預設的類別載入器會使用 mb_strtolower() 將類別名稱轉換為小寫來尋找類別檔案。

順帶一提,這個類別檔案的內容與上面的程式碼等效。
<?php declare(strict_types=1);
namespace
foo;

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

類別 /foo/bar 和 /Foo/Bar 是一樣的。
EVODelavega
10 年前
只是想回應 simast at gmail dot com 的意見:雖然他說 C 語言的效能比 PHP 好是有道理的,但他的建議是微最佳化。我不是 100% 反對程式碼微最佳化,但如果你要這麼做,就徹底執行。

<?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()
);
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 的目的相違背。

同時,請記住,保持自訂自動載入函式的簡潔是很重要的。這是我的載入器類別:

<?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)進行了優化,如果 require/include 是在全域範圍內完成的(並且不是條件式)。因此,明確地包含您知道每個請求都會使用的檔案是個好主意(但不要使用 *_once)。例如,您可以向上述類別添加一個 "registerProfiledAutoload" 並追蹤您包含的內容,以幫助您確定您可以明確包含的內容(在開發期間,而不是生產環境)。關鍵是盡量不要大量使用自動載入。

如果您必須使用相對路徑,並且不介意必須將檔案名稱改為小寫,那麼 spl_autoload 就可以很好地運作。
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));});
Philip
11 年前
當文件說:「正在實例化的類別(和命名空間)的小寫名稱」時,有點不清楚。

它的實際意思是,參數可以使用任何大小寫,但在 PHP 開始尋找檔案之前,它會被轉換為小寫。這可能是因為在 PHP 中,類別名稱是不區分大小寫的(以及函式名稱和命名空間),因此它需要轉換為某種標準格式。
safak_ozpinar at NOSPAM dot yahoo dot com
17 年前
請注意,檔案副檔名的順序對於效能很重要。您應該將您偏好的檔案副檔名的優先順序設為最高,或者只為您的類別檔案使用一個副檔名。看看這個例子

一些類別檔案

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 - 伊斯坦堡大學,電腦工程學系
Ivan Stojmenovic
12 年前
一個小範例展示如何在您的 MVC、框架應用程式中使用 spl_autoload 函式。例如,將使用 Loader 類別。


<?php

class Loader
{

/**
* Controller Directory Path
*
* @var Array
* @access protected
*/
protected $_controllerDirectoryPath = array();

/**
* Model Directory Path
*
* @var Array
* @access protected
*/
protected $_modelDirectoryPath = array();

/**
* Library Directory Path
*
* @var Array
* @access protected
*/
protected $_libraryDirectoryPath = array();


/**
* Constructor
* Constant contain my full path to Model, View, Controllers and Lobrary-
* Direcories.
*
* @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");
}

/**
*-----------------------------------------------------
* Load Library
*-----------------------------------------------------
* Method for load library.
* This method return class object.
*
* @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);
}
}
}

/**
*-----------------------------------------------------
* Initialize Class
*-----------------------------------------------------
* Method for initialise class
* This method return new object.
* This method can initialize more class using (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('Class name must be string.');
}
if (
null == $library) {
throw new
ISException('You must enter the name of the class.');
}
} catch(
Exception $exception) {
echo
$exception;
}
}

/**
* Autoload Controller class
*
* @param string $class
* @return object
*/

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


/**
* Autoload Model 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);
}
}

/**
* Autoload Library 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);
}
}



}

?>
contato at felipebarth dot com dot br
12 年前
<?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