【PHP】requireとrequire_onceの違いと使い分けは?

2021-09-09PHP

PHPで別ファイルに定義した変数やコードを取り込むための関数として、require命令と`require_onceが命令あります。
両者の動作の違いについて説明した記事はよく見かけますが、使い分けまで踏み込んだ記事は見つけられなかったため、少し調べてみました。

  1. 2021.09.03 初版公開
  2. 2021.09.09 追記
  3. 2021.10.12 改題

requirerequire_onceの違い

公式ドキュメントでは、include_onceの項目で、これらの違いについて触れられています。

include_once命令は、スクリプトの実行時に指定したファイルを読み込み評価します。この動作は、include命令と似ていますが、ファイルからのコードが既に読み込まれている場合は、再度読み込まれないという重要な違いがあります。
(略)
include_onceは、スクリプトの実行時にファイルが複数回読み込まれ、評価される可能性がある場合に、関数の再定義や変数値の再代入といった問題を回避するために一回だけ読み込ませるために使用します。

これによると、require_onceを使えば、同じファイルを複数回requireすることがなくなることがわかります。
そのため、関数の再定義や変数値の再代入が起こるといろいろと困る場面のほうが多いはずなので、普通に使うのであれば、
require_onceを使ったほうがよさそう
です。

逆に、requireが必要な場面ってあるのでしょうか?

reqirerequire_onceの動作を確認してみる

ここで、次のようなファイルを用意し、これをrequirerequire_onceでそれぞれ2回取り込んでみます。

$a = "Hello, world\n";

require版のコード

require 'test.php';
print $a;
$a = "Hello, PHP\n";
require 'test.php';
print $a;

実行結果

Hello, world
Hello, world

require_once版のコード

require_once 'test.php';
print $a;
$a = "Hello, PHP\n";
require_once 'test.php';
print $a;

実行結果

Hello, world
Hello, PHP

このように、requie_onceを使うと、2度目の読み込みが行われていないことがわかります。

関数等の定義がある場合

さらにrequireについて実験してみます。

function f($s)
{
  print $s;
}
require 'test.php';
require 'test.php';

実行結果

PHP Fatal error:  Cannot redeclare f() (previously declared in E:\home\work\php\work\test.php:xx) in E:\home\work\php\work\test.php on line yy

Fatal error: Cannot redeclare f() (previously declared in E:\home\work\php\work\test.php:xx) in E:\home\work\php\work\test.php on line yy

このように再定義されているとして致命的エラーが発生します。さらに、

require "test4.php";
require "test3.php";
require 'test3.php';

などとすると、延々と読み込み続けてしまいます。複数のファイルをrequireしていると、知らないうちにネストしていたということもありそうです。

こうやってみてみると、同じファイルを複数回読み込むメリットがあまり見出せません。
どういうときにrequireを使うのがよいのでしょうか?

動作速度の違い?

Twitter上で「require_onceのほうがファイルを読み込んだかチェックする分動作が遅い」とのコメントを見ました。大規模なプロジェクトでは多数のファイルの読み込みが行われることもあると思いますので、どれくらい違うのか、試しに実験してみました。

実験

for($i = 0; $i < 1000; $i++>) {
  require "test".$1.".php";
}
for($i = 0; $i < 1000; $i++>) {
  require_once "test".$1.".php";
}

あらかじめtest0.phptest999.phpまでの空のファイルを作成しておいてから、このブログのサーバーを動かしているさくらVPS上でコマンドラインから上記のファイルを動かして実験しました。時間の計測にはtimeコマンドを使い、計測時間の変動を考慮して10回の平均をとって評価しました。

平均値(ms)最大値(ms)最小値(ms)
require0.0540.0530.056
require_once0.0550.0540.057

1000個ファイル読み込む処理をしてみたところ、あまり変わらない結果となりました。ファイル名のチェックだけだったら、1回あたりの処理にそれほど時間がかからないのかもしれません。

動的生成されたファイルを読み込む

requireを使う場面があまり思いつかなかったのですが、上の実験を行っている最中にファイルを外部で生成するのであれば、複数回読み込めることにメリットがあることに気づきました。

例えば、外部のファイルを読み込んでパラメータを格納する変数を更新するような場合です。この場合も、PHPの主な使用方法であるWebアプリケーションというよりもコマンドラインからスクリプトとして使うようなイメージになると思いますので、この目的の出番は多くなさそうです。

定型文的なHTMLを読み込む(2021.09.09追記)

最終的にこの使い方が一番多そうな気がしてきました。HTMLをパーツに分けて、PHPのコード中に埋め込むような書き方をする場合、HTML取り込みの部分でrequire, require_onceを使うことになります(もちろんinclude, include_onceでも構わない)。この時、閉じタグなどは同じようなパターンで出現することが多いので、require_onceでは取り込むことができません。requireが必要となってきます。

取り込むHTMLが定型的で何度も出現するような場合は、requireの恩恵が大きくなると言えます。

<div class="container">
  <section>
  </section>
</div>
$name = "izadori";

require "section_begin.php";
echo "<h1>Hello, World</h1>"
require "secition_end.php";

require "section_begin.php";
echo <<<EOF
<h1>Hello, $name</h1>
<h2>Menu</h2>
 :
EOF;
require "secition_end.php";

まとめ

requirerequire_onceの違いと使い分け方法は以下と考えられます。

  1. require_onceはそのソースコード中で一度だけ読み込む。
    1. 関数やクラスの定義がある場合はこちらを使う。
  2. requireはソースコード中で実行されるたびに読み込みなおす。
    1. 関数やクラスは重複定義となるため、致命的エラーとなる。
    2. 変数は読み込んだ値に上書きされる。
    3. 再帰的な読み込み方をしないように注意する必要がある。
    4. 動的に生成するような変数のみが記述されたファイルや、定型文的なHTMLを読み込むのに適している。

通常の使い方だとほぼrequire_onceで困らないかと思います。


おすすめのPHP学習用の教科書です。
UdemyやYouTubeでおなじみ「ともすた(たにぐちまこと)」さんの著書です。

PHP

Posted by izadori