PHPには、ファイル読み込みのための関数(※1)がいくつか用意されています。具体的には、以下の4つです。
- require
- require_once
- include
- include_once
最近ではComposerのオートロードの利用で、これらの利用頻度は減ったかもしれません。しかしそれでもPHPエンジニアにとってはなじみ深いものだと思います。
しかしながら、
- コピペで使うことはあっても、自分の頭で考えて使ったことがない
- 何となくいつも同じのを使っていた
という方も多いのではないでしょうか。私も条件反射レベルで、基本はrequire_once
を使っていました。
本ページでは、あらためてこれらの使い分けや違いなどを考えてみたいと思います。
PHPのファイル読み込み関数の概要
読み込み関数とは
あるPHPスクリプトから、別のファイルを読み込むことを指します。
例えば以下の様なコードをfunctions.phpに記述したとします。
<?php
function greet($name) {
echo "Hello, " . $name . "!";
}
以下の例ではindex.phpというファイルから、funcsions.phpを読み込み、greet()
関数を呼び出すことが可能です。
<?php
// ../function.php, hoge/function.php などパスを指定しても可能
// この例では同じディレクトリにあるので、ファイル名だけでOK
require 'functions.php';
greet('World'); // Prints: Hello, World!
読み込み関数を用いることで、コードをモジュール化し、再利用可能な部品に分割することが可能になります。
特に大規模なプロジェクトや複数のプロジェクトで同じコードを共有する必要がある場合、非常に重要な役割を担います。
種類一覧
PHPでは以下の様な関数が利用できます。似たようなものがこんなにあるので、ついつい違いを忘れがちです(汗)。
- require
- require_once
- include
- include_once
しかもどれを使っても挙動が変わらないケースも多いのがやっかいなところ。処理の内容はどれもわずかに異なるので、違いを明確にしておくことが重要です。
後から詳しく説明していきます。
正確には関数ではなく、言語構造
本ページでは便宜上「関数」と書いていますが、正しくは「言語構造」です。
PHPマニュアルによれば言語構造であり、制御構造でもあるというように読めます。
言語構造は、プログラムの一部を形成する命令やアクションを表現するものです。関数と言語構造はそれぞれ異なる概念と認識しておく必要があります。(これに関してはいつか別記事で書きます)
しかしながら関数と同じように呼び出しは可能。例えばrequire("hoge.php");
と require "hoge.php";
は機能的には全く同じで、PHPのエンジンにとっては同じように解釈されます。
// どれでも機能する。
require("hoge.php");
require "hoge.php";
require 'hoge.php';
require
, require_once,
include
, include_once
が言語構造であるという事実を強調するために、括弧を省略することを好む人もいます(私がそうです)。
一方で、コードの一貫性や視認性を保つために括弧を使用する人もいるかもしれません。
例えばPSR-2という広く採用されているPHPのコーディングスタイルガイドでは、言語構造に対して括弧の使用は任意とされています。そのため、自分自身・またはチームのルールに基づいて選択すると良いでしょう。
どちらのスタイルを選んだとしても、違いを理解しておくこと。そしてプロジェクト内での一貫性を保つことが重要です。
これらの関数の違い
4つも似た機能の関数がありますが、
- ファイルが見つからない場合や読み込むことができなかった場合に
- 処理を停止させる
- そのまま続行させる
- 再度同じファイルを読み込む処理があった場合に
- 読み込む
- 読み込まない
で違いがあります。この組み合わせ2×2で、計4つの関数が存在しているというわけです。
それではここから実際に見ていきましょう。ここではheader.phpというファイルを前提に説明します。
<?php
echo 'header.php読み込み!';
include系
ファイルが見つからない場合や読み込むことができなかった場合、処理をそのまま実行させるのがinclude
系です。
include
<?php
include 'header.php';
// Prints: header.php読み込み!
以下の様に、何度でも読み込むことができます。
<?php
include 'header.php';
// Prints: header.php読み込み!
include 'header.php';
// Prints: header.php読み込み!
もしもheader.phpが見つからなかった場合でも、警告:E_WARNING
を発生させるだけで処理は続行されます。
include_once
indelude
の性質を持ちながら、同じファイルは処理中に1度だけの読み込みに限定するのがinclude_once
です。once=1度だけ、という意味なのでこれは分かりやすいですね。
<?php
include_once 'header.php';
// Prints: header.php読み込み!
include_once 'header.php';
// ※header.phpは2度目なので読み込まない
上記ではheader.phpは1度しか呼ばれません。こちらも、header.phpが見つからなかった場合でも、警告: E_WARNING
を発生させるだけで処理は続行されます。
今回のようなシーンではあまり優位は感じないと思いますが、1度しか読み込みたくない場合。例えば設定やクラスが含まれるなどを読み込む際は1度で良いので_onceをつけた方が良いでしょう。
require系
ファイルが見つからない場合や読み込むことができなかった場合、処理を停止させるのがrequire
系です。読み込み対象のファイルが「必要不可欠」な場合はこちらです。
require
include
と同様で、何度でも読み込むことができます。
<?php
require 'header.php';
// Prints: header.php読み込み!
require 'header.php';
// Prints: header.php読み込み!
include
と違うのは、先ほど触れたとおりエラー時です。
この例でheader.phpが見つからなかった場合は、致命的なエラー:E_COMPILE_ERROR
を発生させ、PHPの処理は終了します。
require_once
include_once
と同様に、1度しか読みこみません。
<?php
require_once 'header.php';
// Prints: header.php読み込み!
require_once 'header.php';
// ※header.phpは2度目なので読み込まない
header.phpが見つからなかった場合は、致命的なエラー:E_COMPILE_ERROR
を発生させ、処理は終了します。include_once
との違いはそこです。
どれを選択すれば良い!?
実際のプログラミングの際、どのように選択すれば良いかを考えてみます。あくまで私の考えですが、1つずつ考えていけば最適なものを選べると思います。
require系とinclude系はどちら?
まず、require
系とinclude
系のどちらか適しているかを考えてみましょう。
復習になりますが、require
系とinclude
系では、ファイルを読み込むことができなかった場合の挙動が異なります。
- include系→警告(E_WARNING)が発生し、スクリプトの実行は続行
- require系→致命的なエラー(E_COMPILE_ERROR)を発生させ、スクリプトの実行を停止
ですから、読み込む対象がスクリプト実行にとっ「必要(つまりrequire
)であるかで判別できると思います。
例えば、
- ライブラリやフレームワークの読み込み
- 設定ファイルの読み込み
- クラス定義の読み込み
などは、読み込めなかったら処理が続行できないことが多いですよね。そういった場合はエラーとして停止させた方が良いので、require
系が適していると思います。
逆に、読み込みに失敗してもスクリプトの続行に影響しないことが明白であれば、include
系で良いかもしれません。
onceにするかどうか
require
系かinclude
系のどちらが相応しいか分かったところで、次にonceにするかしないかを考えます。
こちらも復習になりますが、require_once
, include_once
のように、_once
がついている関数は、コード実行中に1度しか呼ばれません。
対象ファイルの読み込みが必要なのは1度だけなら_once
付にしましょう。そうでないなら、_once
無しが良いかもしれません。
作者はrequire_onceの使用が多いです。繰り返し同じファイルを読む必要があることはあまりないからです。
余談:処理速度の違いは!?
そんなことより処理速度を第一に選びたい!
……という方もいるかもしれません。私もそう考えたことがありました。
たしかに_once
系は、同じファイルがすでに読み込まれているかどうかをチェックするため、require
やinclude
よりもわずかに遅くなる可能性はあります。
しかし、この性能差はほとんどのアプリケーションでは無視できる程度のもの。それよりも重要なのは、正しく美しくプログラミングできているかです。
そのため、処理速度よりも、それぞれの関数の挙動の違いと適切な使用シーンを理解することの方が重要と考えます。
まとめ
近年はComposerのオートローディングだけで済むことも多く、require
等の利用は減ってきたと思います。
しかしながら、少し前に書かれたWebシステムでは現在でも大量に使われています。全く使わなくなることはないでしょう。
こういった部分の違いを明確にしておくことでPHPの基礎力を身につけることができます。私も知ってはいましたが、まとめることで改めて良い勉強になりました!
コメント