include 'header.php';は、スクリプトのその場所で、貼り付けたかのようにほかのPHPファイルのコードを実行します。require 'header.php';も同じことをしますが、ファイルを読み込めないとき、requireは致命的エラーでスクリプトを止め、includeは警告を表示するだけで続けます。最初によく使うのは、すべてのページで共有するヘッダーとフッターです。
このブロックは、includeするファイルがあるよう先にheader.phpとfooter.phpを書き出します。実行してPageタブを見てください。
includeされるファイルは普通のPHPファイルです。<?= ?>タグを含むHTMLを書け、requireの前にセットした$title変数も見えます。タイトルを変えてもう一度実行してみてください。ヘッダーをrequireしているすべてのページが、その1つのファイルの変更を反映します。
includeとrequireの違い
違いは、ファイルがないか読めないときに何が起こるかだけです。includeは2つの警告を表示し、falseに評価され、スクリプトは続きます。
Warning: include(sidebar.php): Failed to open stream: No such file or directory in /home/index.php on line 2
Warning: include(): Failed opening 'sidebar.php' for inclusion (include_path='.:/usr/share/php83') in /home/index.php on line 2
requireは同じ警告を表示してからErrorを投げ、何かがキャッチしない限りスクリプトを終わらせます。
PHP Warning: require(config.php): Failed to open stream: No such file or directory in /home/index.php on line 2
PHP Fatal error: Uncaught Error: Failed opening required 'config.php' (include_path='.:/usr/share/php83') in /home/index.php:2
そのため、ページがそれなしでは動かないもの(設定、関数ライブラリ、クラスのファイル)にはrequireを、任意の部分にはincludeを使います。正当に存在しないこともある部分は、警告に頼らず先に確認しましょう。
出力:
Spring sale: 20% off
banner.php included, include returned int(1)
sidebar.php not found, skipped
include_onceとrequire_once
関数やクラスを定義するファイルは1回しか読み込めません。関数がすでに存在するので、2回目の読み込みは致命的エラーになります。
Fatal error: Cannot redeclare greet() (previously declared in /home/helpers.php:2) in /home/helpers.php on line 2
これは、2つのファイルがそれぞれrequire 'helpers.php'したとたんに起こります。require_onceとinclude_onceは、どのファイルがすでに読み込まれたかを覚えていて、2回目は飛ばしてtrueを返します。
出力:
int(1)
bool(true)
bool(true)
Hello, Ada
何かを宣言するファイルには_onceの形を使い、2回以上出力したいテンプレートには普通のincludeを使います。Composerを使うプロジェクトではオートローダーがクラスのファイルを読み込んでくれるので、クラスのためのrequire_onceの呼び出しはほとんどなくなります。Composerを参照してください。
includeしたファイルから値を返す
includeしたファイルのトップレベルのreturnは、そのファイルを止め、includeやrequireの式に値を返します。これできれいな設定ファイルが作れます。グローバル変数はなく、好きな名前に代入する値があるだけです。
出力:
My Shop
shop
bool(false)
Laravelの設定ファイル(config/app.php、config/database.phpなど)はこの方法で動いています。
includeしたファイルの変数とスコープ
includeしたコードは、includeした行のスコープで実行されます。スクリプトのトップではすべてのグローバル変数が見え、関数の中ではその関数のローカル変数だけが見えます。2つ目のルールを使えば、小さなテンプレートレンダラーが作れます。テンプレートに見せるべき変数をちょうどローカル変数として持つ関数です。
Pageタブには、1つのテンプレートファイルから描画された両方のリストが表示されます。includeはrender()の中で実行されるので、テンプレートには$headingと$productsが見えますが、$secretは見えません。テンプレートで使っているforeach ... endforeachの形は、PHPがHTMLテンプレート向けに用意している別の構文です。
includeのパスと__DIR__
'helper.php'のようなパスは、includeを含むファイルからの相対では解決されません。PHPはinclude_pathの設定(ふつうは現在の作業ディレクトリを表す.で始まります)を探し、そのあとでやっとincludeしているファイル自身のフォルダーを探します。そのためpartials/nav.phpの中のinclude 'helper.php'は、プロジェクトのルートにあるまったく別のhelper.phpを読み込むことがあります。現在のファイルのディレクトリを表す__DIR__を使えば、推測の余地がなくなります。
出力:
loaded the root helper.php
loaded partials/helper.php
__DIR__ in nav.php is partials
すべてのincludeを__DIR__ . '/relative/path.php'の形で書きましょう。作業ディレクトリはスクリプトの起動のされ方(Webサーバー、cronジョブ、別のフォルダーからのコマンドライン)によって変わりますが、__DIR__は決して変わりません。
ユーザーが名前を指定したファイルを決してincludeしない
最初のルーターによくあるのが、URLからページ名を読むinclude $_GET['page'] . '.php';です。これでは訪問者がサーバー上のどのファイルを実行するかを選べてしまいます。たとえば?page=../../config(ローカルファイルインクルージョン)で、古い設定ならほかのサーバーのファイルさえ選べます。代わりに、許可された名前をファイルに対応させましょう。ブロックを実行してリンクをクリックすると、クリックのたびに別の$_GET['page']でスクリプトがもう一度実行されます。
requireに届くのは$pagesにある3つの名前だけで、../secretのリンクは「Not found」のページになります。リクエストの値を安全に読む方法は_POSTで扱っています。
よくある質問
PHPのincludeとrequireの違いは何ですか?
どちらもほかのPHPファイルを読み込んで実行します。ファイルを読み込めないとき、requireは致命的エラーでスクリプトを止め、includeは警告を表示してfalseを返し、スクリプトを続けます。設定や関数ライブラリのように、ページがそれなしでは動かないファイルにはrequireを使います。
requireではなくrequire_onceを使うべきなのはどんなときですか?
関数、クラス、定数を定義するファイルにはrequire_onceを使います。そのようなファイルを2回読み込むと致命的エラー(Cannot redeclare)になりますが、require_onceはすでに読み込んだファイルを飛ばします。何度も出力したいテンプレートには普通のincludeを使います。
includeしたPHPファイルは値を返せますか?
返せます。includeしたファイルのトップレベルのreturnはそのファイルを終わらせ、includeやrequireの式の値になります:config.phpにreturn ['debug' => true];と書いて$config = require 'config.php';とします。returnがなければ、includeの値は1です。
includeしたファイルから自分の変数にアクセスできますか?
できます。includeしたコードは、includeした行のスコープで実行されます。スクリプトのトップではグローバル変数が見え、関数の中ではその関数のローカル変数だけが見えます。そのファイルが作った変数も同じスコープに置かれます。
include('file.php')とinclude 'file.php'のどちらで書くべきですか?
どちらも動きます。includeとrequireは関数ではなく言語構造なので、括弧はパスを囲んでいるだけです。ほとんどのスタイルガイドは括弧なしでrequire 'file.php';と書きます。