こちらの記事でrequireについて検証しました。
その際コメントでrequireにもスコープがあって必ずしも一度宣言すればよいわけではないとご指摘を頂きました。ご指摘いただけると学習になるので本当に助かります!!
今回は続編としてrequireのスコープについて検証します。
いきなりですが公式ドキュメントの文章を引用します。
ファイルが読み込まれるとそのファイルに含まれるコードは、 includeもしくはrequireが実行された 行の変数スコープを継承します。 呼び出し側の行で利用可能である全ての変数は、読み込まれたファイル内で利用可能です。 しかし、読み込まれたファイル内で定義されている関数やクラスはすべて グローバルスコープとなります。
https://www.php.net/manual/ja/function.include.php
初見ではなかなか悩ましい文章でした。
実行された行のスコープを継承しますと言いつつグローバルスコープとなります??ってなりますが今回の検証を終えればやっと公式の言いたいことが少しわかるかと思います!
では準備に取り掛かりましょう。材料はたったの2つ!(webサーバは前提というあるある)
材料
材料となるファイルはすべてwebサーバの同じディレクトリの中に格納してください。
一つ目はただクラスと変数が定義してあるだけの読み込み用のファイルです。
<?php
//読込み用ファイル
$a = 100;
class a{}
二つ目はブラウザでアクセスするファイルです。
htmlのh1タグで3つの変数を表示するプログラムです。可読性のためにソースの中にコメントとして何を目的としているのか記載します。
<?php
function a()
{
//変数とクラスを含んでいるファイルです。変数はクラスの外に$aとして定義してあります。
require 'YomikomiFile.php';
//ファイルが読み込まれるとそのファイルに含まれるコードは、 includeもしくはrequireが実行された 行の変数スコープを継承します。
//すなわち関数の中のでrequireしたので関数内だけのローカルスコープになります。
//requireがローカルスコープなので同じ関数からならアクセスできるはずということでYomikomiFile.phpの$aにアクセスしています。
return $a;
}
//$rsltは関数の外にいるため関数から間接的に値を貰います。
//$rsltが表示出来たら、関数の中でrequireされたファイルであれば同じ関数の中からアクセスできることが証明されます。
$rslt = a();
//読み込まれたファイル内で定義されている関数やクラスはすべて グローバルスコープとなります。
//つまりYomikomiFile.phpで定義されているaクラスもグローバルスコープだから問題なくインスタンス化できるはず
$class = new a;
?>
<html>
<h1>
<?php
//問題なく表示されればクラスはグローバルスコープとして使えることが証明される。
var_dump($class);
?>
</h1>
<h1>
<?php
//問題なく表示されれば関数の中でrequireされたファイルであれば同じ関数の中からアクセスできることが証明される
var_dump($rslt);
?>
</h1>
<h1>
<?php
//これはグローバルスコープになるクラスでも関数でもないし、
//関数内のローカルスコープも及ばないので公式曰くエラーになることが仕様となる
var_dump($a);
?>
</h1>
</html>
実験
材料が用意出来たらブラウザからReqScopeStart.phpにアクセスしてみましょう!
うまくいけばブラウザに下記が表示されるはずです。
検証
改めて公式の文章を見てみましょう!
ファイルが読み込まれるとそのファイルに含まれるコードは、 includeもしくはrequireが実行された 行の変数スコープを継承します。 呼び出し側の行で利用可能である全ての変数は、読み込まれたファイル内で利用可能です。 しかし、読み込まれたファイル内で定義されている関数やクラスはすべて グローバルスコープとなります。
https://www.php.net/manual/ja/function.include.php
一行ずつ違うこと説明してたんですね。解釈しやすい順にみていきましょう。
しかし、読み込まれたファイル内で定義されている関数やクラスはすべて グローバルスコープとなります。
これは関数の中や関数の外やらどこでファイルが読み込まれようと、一貫して読み込まれたファイル内で定義しているクラスや関数はグローバルスコープになるという意味のようです。
実際に実験結果もクラスにはアクセスできたけど変数にはアクセスできませんでした。
呼び出し側の行で利用可能である全ての変数は、読み込まれたファイル内で利用可能です。
呼び出したファイルの変数を呼び出されたファイルが使うことができます。実際呼び出された側のファイルで使えることを確認はできましたがルールまではまだ理解できていません。これは今回扱っていないので機会があればまた調べたいところです。
ファイルが読み込まれるとそのファイルに含まれるコードは、 includeもしくはrequireが実行された 行の変数スコープを継承します。
この文章が本当に悩ましかったです。今も6割くらいしか理解できていない気がしますが実験は成功したので安心しました。
関数とクラスに関しては常にグローバルスコープなのでスコープをそれほど意識する必要はないように感じましたが、クラスや関数に含まれていない変数についてはrequire呼び出し行のスコープが適応されるのでそこだけ注意ということかと思います。
今回の実験ではYomikomiFile.phpの$aが関数でもクラスでもなかったためrequire呼び出し行のスコープ、すなわち関数の中だけのローカルスコープが適用されていました。なので関数外からアクセスしようとしてもできなかったということになります。
最後に
なるべく正確な情報を発信できるように心がけておりますが間違えた情報を発信していることもあるかと思います。
そういう時はコメントでご指摘いただけますと幸いです!
どうぞ宜しくお願い致します。