こんにちは、かつコーチです。
前回は無名関数・クロージャを解説しました。
今回は、PHPで別のファイルを読み込むときに必ず出てくる4つの命令、require・require_once・include・include_once の違いを解説します。
名前がよく似ているうえに、どれを使っても「一応動く」ことが多いので、なんとなく使い分けている人も多いのではないでしょうか。
私自身、駆け出しの頃はこの4つを完全に感覚で選んでいて、あるとき本番環境で痛い目を見た経験があります。
その話も含めて、しっかり整理していきます。
なぜファイルを分割して読み込む必要があるのか
1つのファイルに全部書くと何が困るのか
PHPでWebサイトを作っていくと、共通で使う部品がどんどん増えていきます。
- ヘッダー・フッターのHTML
- データベース接続の設定
- 共通で使う関数
こうした部品を毎回すべてのファイルにコピペしていたら、修正が必要になったときに全ファイルを1つずつ直さなければなりません。
そこで登場するのが、別のPHPファイルを、今のファイルの中に読み込むという考え方です。
これを実現するのが require・require_once・include・include_once の4命令です。
基本のイメージ
例えば、共通のヘッダーを別ファイルに切り出しておくとします。
<?php
// header.php
?>
<header>
<h1>かつコーチのブログ</h1>
</header>
これを各ページから読み込むと、次のように書けます。
<?php
// index.php
require 'header.php';
?>
<main>
<p>ここが本文です。</p>
</main>
header.php の中身が、あたかも index.php に直接書いたかのように展開されます。
4つの命令の違い
require と include の違い:エラー発生時の挙動
require と include の一番大きな違いは、ファイルが見つからなかったときの挙動です。
| 命令 | ファイルが見つからない場合 |
|---|---|
require | 致命的エラー(Fatal Error)で処理が停止する |
include | 警告(Warning)が出るが、処理は続行される |
実際にコードで確認してみましょう。
<?php
// requireの場合
require 'not_found.php';
echo "この行は実行されません";
Fatal error: Uncaught ValueError: require(): Argument #1 ($filename) must not contain any null bytes in ...
(PHPのバージョンによってメッセージ文言は異なりますが、致命的エラーとして処理が止まります)
<?php
// includeの場合
include 'not_found.php';
echo "この行は実行されます";
Warning: include(not_found.php): Failed to open stream: No such file or directory in ...
この行は実行されます
require は「このファイルがないと処理が成立しない」という必須ファイルを読み込むときに使います。
include は「なくても処理自体は続けられる」という補助的なファイルを読み込むときに使うのが基本の考え方です。
_once が付くとどうなるのか
require_once と include_once は、それぞれ require と include に「同じファイルを二重に読み込まない」という仕組みが加わったものです。
<?php
// config.php
$dbHost = "localhost";
$dbName = "sample_db";
<?php
// a.php
require 'config.php';
require 'config.php'; // 2回読み込んでしまっている
require を2回書くと、config.php の中身が2回展開されます。
変数の再代入くらいなら問題になりにくいですが、関数やクラスの定義が2回読み込まれると致命的エラーになります。
<?php
// functions.php
function greet() {
echo "こんにちは";
}
<?php
require 'functions.php';
require 'functions.php'; // 同じ関数を2回定義しようとしてエラーになる
Fatal error: Cannot redeclare greet() (previously declared in ...)
これを防いでくれるのが require_once です。
<?php
require_once 'functions.php';
require_once 'functions.php'; // すでに読み込み済みなので何もしない
require_once を使えば、同じファイルが何度指定されても、実際に読み込まれるのは最初の1回だけになります。
つまずきやすいポイント:使い分けの判断ミス
かつコーチが実際にやらかした失敗
私が新人だった頃、複数のページから共通の関数ファイルを include で読み込む構成にしていたことがあります。
ある日、サーバーの設定ミスでその関数ファイルへのパスが一時的に見つからない状態になりました。
include だったため、エラーは警告レベルで表示されるだけで処理は止まらず、関数が定義されていない状態のままページの処理が最後まで進んでしまったのです。
結果、決済処理の途中で「関数が存在しません」という別のエラーが発生し、原因調査にかなりの時間を使ってしまいました。
この経験から、「処理の前提になる必須ファイルは、必ず require 系を使う」ということを徹底するようになりました。
❌ Before:必須ファイルを include で読み込んでしまう
<?php
// 決済処理に必要な関数ファイルなのにincludeを使っている
include 'payment_functions.php';
$result = processPayment($amount); // 関数が読み込めていないとFatal Errorになる
ファイルが読み込めなかった場合、警告は出るものの処理は止まらず、後続の processPayment() の呼び出しで「未定義関数」エラーが発生してしまいます。
エラーの発生場所が本来の原因(ファイル読み込み失敗)から離れてしまうため、原因の特定に時間がかかります。
✅ After:必須ファイルは require_once で読み込む
<?php
// 処理に絶対必要な関数ファイルはrequire_onceで読み込む
require_once 'payment_functions.php';
$result = processPayment($amount); // 読み込みに失敗した時点でFatal Errorになり、原因箇所がすぐ分かる
require_once にしておけば、ファイルが見つからない時点で処理が止まり、エラーメッセージにも「どのファイルの読み込みに失敗したか」が明示されます。
「なくても動いてほしいものは include、動いてもらっては困るものは require」という基準で選ぶと、迷いにくくなります。
どう使い分ければいいか:判断フロー
実務での基準
私が実務で使い分けている基準を整理すると、次のようになります。
- その処理を続けるために絶対に必要なファイルか? → Yesなら
require系 - 同じファイルを複数箇所から読み込む可能性があるか? → Yesなら
_onceを付ける
結論として、実務では require_once を使うケースが圧倒的に多いです。
設定ファイルや関数ファイル、クラスファイルなど、二重読み込みを避けたい・必須である、というケースがほとんどだからです。
include を使うのは、「あれば表示する、なくても致命的ではない」という限定的な場面(例:一部のオプション表示用パーツなど)に絞るとよいでしょう。
オートロードとの関係
余談ですが、PHPでクラスをたくさん扱うようになると、require を1つずつ書いていくのは現実的ではなくなってきます。
そこで登場するのが「オートロード(autoload)」という仕組みで、クラスが使われたタイミングで自動的にファイルを読み込んでくれます。
Laravelなどのフレームワークでは、このオートロードの仕組みが標準で整えられているため、require を意識する場面はぐっと減ります。
とはいえ、素のPHPでファイルがどう読み込まれているかを理解しておくと、フレームワークの裏側の動きも理解しやすくなります。
まとめ
この記事のポイント
requireはファイルが見つからないと致命的エラーで処理が止まるincludeはファイルが見つからなくても警告のみで処理が続行されるrequire_once・include_onceは同じファイルの二重読み込みを防いでくれる- 処理に必須なファイルは
require(できればrequire_once)を使うのが基本 - Laravelなどのフレームワークではオートロードの仕組みが
requireを肩代わりしてくれる
次に読むべき記事
ファイルを分割して読み込めるようになったら、次はPHPでよく使う文字列操作の関数を押さえていきましょう。
→ 次の記事:PHPの文字列操作関数まとめ:strlen・substr・str_replaceの使い方