PHP 提供四種檔案載入語句,看似相似但行為差異關鍵。本文系統對比 include、require、include_once、require_once 的錯誤處理、載入邏輯、效能特徵、適用場景與現代替代方案 (Composer 自動載入)。
核心差異對比表
| 語句 | 檔案不存在 | 語法錯誤 | 重複載入 | 回傳值 | 典型用途 |
include | Warning,繼續執行 | PHP 4.3.5+ 停止 | 允許重複 | 成功 1,失敗 false | 模板、可選配置、非關鍵檔案 |
require | Fatal Error,腳本終止 | 停止 | 允許重複 | 無 (終止) | 核心類別、關鍵配置、必須存在檔案 |
include_once | Warning,繼續 | 停止 | 忽略重複 | 成功 1,失敗 false | 函式庫、類別定義、防重複定義 |
require_once | Fatal Error,終止 | 停止 | 忽略重複 | 無 | 核心類別、單例載入、防重複定義 |
行為細節深度解析
1. 錯誤處理機制
<?php
// include: 產生 Warning,腳本繼續
include 'missing.php'; // Warning: Failed opening 'missing.php'
echo "繼續執行\n"; // 會輸出
// require: 產生 Fatal Error,腳本立即停止
require 'missing.php'; // Fatal error: Failed opening required 'missing.php'
echo "不會執行\n"; // 不會輸出
// 實際專案建議:生產環境 display_errors=Off,錯誤記錄到 log
2. 重複載入防護
<?php
// a.php
$config = ['app_name' => 'MyApp'];
function helper() { return 'helper'; }
// 主程式
include 'a.php';
include 'a.php'; // 重複執行:$config 覆蓋、函數重複定義 Fatal Error
include_once 'a.php';
include_once 'a.php'; // 第二次被忽略,安全
3. 回傳值與作用域
<?php
// return.php
return ['db' => 'mysql'];
// 使用
$config = include 'return.php'; // $config = ['db' => 'mysql']
// require 同理,但失敗時不返回
// 作用域:include 在函數內呼叫,變數為區域變數
function loadConfig() {
include 'config.php'; // $config 只在函數內可見
return $config;
}
4. 路徑解析規則
- 相對路徑:相對於 **當前執行腳本** (entry script),而非被 include 的檔案
- 絕對路徑:直接解析
include_path (php.ini) 會被搜尋
<?php
// index.php 在 /var/www/
// lib/config.php 在 /var/www/lib/
// lib/db.php 在 /var/www/lib/ 引用 config.php
// lib/db.php
include 'config.php'; // 相對於 index.php -> /var/www/config.php (錯誤!)
// 正確做法:使用 __DIR__
include __DIR__ . '/config.php'; // /var/www/lib/config.php ✓
效能特徵
| 語句 | 編譯快取 (OpCache) | 重複檢查開銷 | 記憶體 |
| include/require | ✅ 被快取 | 無 | 正常 |
| include_once/require_once | ✅ 被快取 | 極小 (查詢已載入表) | 略高 (維護載入表) |
關鍵點:PHP 7+ OpCache 啟用後,_once 版本效能差異可忽略。**首選 require_once 載入類別/函式庫**,確保單一載入與錯誤即時暴露。
現代最佳實踐:Composer PSR-4 自動載入
手動 include/require 已是反模式。現代 PHP 專案 (Laravel, Symfony, 獨立庫) 全部使用 Composer 自動載入:
1. 定義命名空間對應 (composer.json)
{
"autoload": {
"psr-4": {
"App\\": "src/",
"MyLib\\": "lib/"
},
"files": ["src/helpers.php"] // 全域函式檔
}
}
2. 執行生成自動載入器
composer dump-autoload -o # -o 優化為 class map
3. 入口檔案單一引入
<?php
// public/index.php
require_once __DIR__ . '/../vendor/autoload.php';
// 之後直接使用類別,無需任何 include
use App\Controllers\UserController;
use MyLib\Utils\StringHelper;
$ctrl = new UserController();
echo StringHelper::slug('Hello World');
遷移指南:從手動 include 到自動載入
- 整理專案結構,依 PSR-4 規範目錄 (如
src/Controller/UserController.php)
- 類別檔案頂部加入
namespace App\Controller;
- 移除所有
include/require 類別檔案的呼叫
- 全域函式集中到
helpers.php,在 composer.json files 註冊
- 入口檔案僅保留
require 'vendor/autoload.php';
- 執行
composer dump-autoload -o
特殊場景仍需手動載入
- 動態載入插件/模組:
foreach (glob('plugins/*/bootstrap.php') as $f) require_once $f;
- 條件式載入配置:
if (file_exists($envFile)) require $envFile;
- 模板引擎編譯輸出:
include $compiledTemplatePath;
- 舊專案逐步遷移過渡期
常見誤區
include_once 效能差很多
- OpCache 下差異微乎其微,安全性收益遠大於成本
- 用
include 載入類別定義
- 重複請求會導致 "Cannot redeclare class" Fatal Error
- 相對路徑以為相對於當前檔案
- 實際相對於執行入口,必須用
__DIR__
require 有回傳值可接收
require 失敗直接 Fatal Error,無回傳值;只有 include 有回傳值
總結:**類別/函式庫 → require_once (或更好:Composer 自動載入)**,**模板/可選配置 → include**。現代專案應盡早遷移至 PSR-4 自動載入,消除手動路徑管理負擔,享受 IDE 完整支援與部署一致性。
- 上一篇文章: Laravel 整合阿里雲 OSS Composer 包:johnlui/aliyun-oss 使用完整指南
- 下一篇文章: PHP MySQL 結果集獲取函數差異詳解:mysql_fetch_row、assoc、array 與 object
Copyright ©
程式碼之家 All Rights Reserved