質問: **Q1.`realpath`と`__FILE__`の共通点** ・何れも「サーバのファイルシステム上の絶対パス」を返すのでしょうか? ・「正規化された絶対パス名」の意味が理解できません。シンボリックリンクの元の位置、という意味? --- **Q2.realpathの使い所が分からないのですが、** ・シンボリックリンクを使用していない場合は、全て「`__FILE__`」で代用できるでしょうか? --- **Q3.組み合わせについて** ・そもそも、realpathは単独で使用するもの? ・それとも「`__FILE__`」と併用するもの? ・あるいはどちらでも良い?? --- **Q4.例えばですが** ・下記例は常に同じ結果となりますか? ・「`__FILE__`」で既に「正規化された絶対パス」を返しているので、その上でさらにrealpathを行う意味はない? ・「正規化された絶対パス」をさらに「正規化された絶対パス」処理してもエラーとはならない? ・単なる無駄な処理? ``` include( realpath( dirname( __FILE__ ) ).'/a/b.php' ); include( ( dirname( __FILE__ ) ).'/a/b.php' ); ```
回答: ***Q1.realpathと__FILE__の共通点*** ***・何れも「サーバのファイルシステム上の絶対パス」を返すのでしょうか?*** はい。 ***・「正規化された絶対パス名」の意味が理解できません。シンボリックリンクの元の位置、という意味?*** シンボリックリンクの元の位置に変換することも含まれますが、それだけではありません。きちんと理解するには、Unixのファイルシステムでのパス名の表し方に冗長性(余計なものを挟み込んで長ったらしく書くことができる)があると言うことを理解しておかないといけません。 例えば、次のようなディレクトリ構成でファイルが配置されているとします。 ``` /var/ www/ php/ common/ utils.php pages/ home/ index.php ``` この時、`utils.php`を`index.php`の中からアクセスする場合、`/var/www/php/common/utils.php`のような絶対パスで指定せずに、`index.php`の存在するディレクトリからの相対パスで、`../../common/utils.php`と表すことがあるのはご存知かと思います。 相対パスは基準になる位置が変わってしまうと意味が変わってしまいますから、システム側(この場合PHPの中の何か)は、手っ取り早く絶対パスを作るためにこんな表現を作ることがあります。 ``` /var/www/php/pages/home/../../common/utils.php ``` Unix型のファイルシステムを今すぐ試せる環境があれば、このような`..`を含むパスを指定しても普通にそのファイルにアクセスできることがわかります。 これは便利な機構ではあるのですが、使い方によっては不便になる時があります。例えば、現在のPHPの処理系はよく使うファイルをキャッシュしてメモリに保持できるようになっているわけですが(*)、単純な文字列でパスを比較して`/var/www/php/common/utils.php`と`/var/www/php/pages/home/../../common/utils.php`とは違うファイルなんだと判定されると、既に`utils.php`はメモリに読み込んであるのに、また同じものをメモリに保持してしまうことになります。 そこでそのような用途のために「パスを表す文字列ではこれが正しい形」と言うのを決めてやり、その正しい形に変換することを「正規化する」と言うわけです。 上記の例でいうと、`/var/www/php/common/utils.php`と`/var/www/php/pages/home/../../common/utils.php`とはどちらも有効な「絶対パス」ですが、「正規化された絶対パス」としては、`/var/www/php/common/utils.php`だけを表すことになります。ちなみに「パス」のことを「パス名」と言うのは古いUnixでの習慣くらいに思って「名」は無視してください。(英語でもpathとpath nameは同義に使います。) 当然ながら、シンボリックリンクはリンクじゃない元の位置のパスに置き換え、`../..`などの冗長な表現は省いた形が正規化された形(正規形)です。 ※Unixのファイルパス以外の話をしている場合、「正規化」は全然違うことを表しますが、ものすごぉく大きな立場から見ると同じような概念を表していると言って良いでしょう。 (*) 実際にPHPに標準搭載のキャッシュ機能はもっと複雑です。「PHPのキャッシュ機能」について学習を進められる場合、ここに書かれた説明は単なるたとえ話でPHPのキャッシュ機能そのものを説明しているのではないことにご注意ください。 ***Q2.realpathの使い所が分からないのですが、*** ***・シンボリックリンクを使用していない場合は、全て「__FILE__」で代用できるでしょうか?*** できません。 そもそも`realpath`は関数で、`__FILE__`は定義済み擬似定数で用途が異なります。 先の例の`index.php`の中では、`__FILE__`の値は`'/var/www/php/pages/home/index.php'`という文字列になりますし、`utils.php`の中では`'/var/www/php/common/utils.php'`という文字列になります。 一方`realpath`の方は関数ですから、パスを表す文字列を引数として使うことになります。例えば`realpath('/var/www/php/pages/home/../../common/utils.php')`の結果は`'/var/www/php/common/utils.php'`という正規化された絶対パスになります。 かなり上の方で書いたように、実際のファイルシステム的には`..`なんかの冗長な表現が含まれていても大抵は動くのですが、「なんか気持ち悪い」「もしかして不具合が出るかも」程度の理由で、文字列からファイルパスを作ったりした後に`realpath`が使われている場合も多いです。 ***Q3.組み合わせについて*** ***・そもそも、realpathは単独で使用するもの?*** ***・それとも「__FILE__」と併用するもの?*** 上記のように`realpath`は関数ですから、単独で使用することはありません。ただし、組み合わせられる(引数として渡される)のは`__FILE__`ではなく、`__DIR__`かもしれませんし、そんな擬似定数以外の文字列式かもしれません。 ***・あるいはどちらでも良い??*** それぞれ目的も使い方もちがうので、「どちらでも良い」なんてことはありません。目的・用途によって正しく使い分けてください。 ***Q4.例えばですが*** ***・下記例は常に同じ結果となりますか?*** (Unix互換のファイルシステムを使用しているとして)はい。 ※実用レベルのOSで同じ結果にならないようなファイルシステムを採用している例や、どんなファイルシステムにしたら同じ結果にならないようにできるかと言うのは思いつきませんが、絶対にそんなものはありえないと断言はできません。ただ、通常のPHPを動作させる環境で夢のような別OSを想定しても仕方ないので、以下では上記の仮定が成り立つものとします。 ***・「__FILE__」で既に「正規化された絶対パス」を返しているので、その上でさらにrealpathを行う意味はない?*** 書かれている処理が`realpath(__FILE__)`なら即YESですね。`realpath( dirname( __FILE__ ) )`についても、正規化されたパスを与えられた時に`dirname()`の結果が正規化されていないことは考えられないので、最初の仮定の下YESです。 ***・「正規化された絶対パス」をさらに「正規化された絶対パス」処理してもエラーとはならない?*** なりません。必ず元のパスと同じ文字列が得られます。 ***・単なる無駄な処理?*** ご掲載の2行のコードだけを見るなら、上の方は「無駄な処理」をしています。 ただ、かっこの位置を少し変えて、 ``` include( realpath( dirname( __FILE__ ).'/a/b.php' ) ); ``` とするなら、少しは意味があるかもしれません。あちこちにこの行がコピペされて使い回されていく間に`'/a/b.php'`の部分は他のパスや変数に置き換わる可能性もあるでしょうから、この回答の **Q2** 末尾に書かせてもらったように、その辺も考えて「文字列からファイルパスを作ったりした後に」必ず`realpath`をかませる、と言うのであれば、特定の場合には無駄でも意味があるコーディングスタイルと言えるでしょう。 しかしながら、ご掲載のように、 ``` include( realpath( dirname( __FILE__ ) ).'/a/b.php' ); ``` の場合だと、せっかく`realpath( dirname( __FILE__ ) )`で確実に(実は無駄ですが)正規化しているのに、その後文字列演算で違うパスを作ってしまっています。「なんとなく」で理由もわからずに`realpath`を使っているのか?と言う気がします(*)。最初に書いた結論通りですが、「無駄な処理」です。 (*) `__FILE__`の変更履歴に「4.0.2 `__FILE__` に常に絶対パスを含め、シンボリックリンクも解決するようになりました。 これより前のバージョンでは、場合によっては相対パスが含まれていることもありました。」と言う記載がある(ちなみに私がPHPを触り始めるより遥か以前の変更です)ので、古い古いPHPの頃にそんな書き方が身についた人のコード(あるいはそう言うコードを真似ただけのコード)なのかもしれません。