はじめに
今回は素のPHPでアプリ開発をしている際に発生した相対PATHによるエラーです。
高機能なフレームワークを使用していると、実行したスクリプトの場所によるエラーが発生しないので、はまりポイントだなと思いました。
ファイル構造
以下のような構造のプロジェクトがあるとします
app/
src/
- main.php
- sub.php
相対PATHとは?
現在のファイル(カレントディレクトリ)から見た相対位置で指定
// main.php
require './sub.php'
// ./ 同じディレクトリ
// ../ 1つ上のディレクトリ
絶対PATHとは?
ルート(一番上の階層)からのフルPATH
// main.php
// __DIR__は現在のファイルまでのPATHが入ります。
require __DIR__ . '/sub.php';
index.php
require './sub.php'
この時上記は正しく機能します。index.phpはsub.phpと同じ階層です。
エラーが発生する例
構造を少し変えます。
app/
src/
- main.php
- sub.php
dir/
- add.php
add.phpからmain.phpを読み込んでみます
require '../main.php'
main.phpを開いた時、つまり
localhost:8000/main.phpでエラーは発生しません。
localhost:8000/dir/add.phpを開いた時にエラーが発生します。
add.phpが起点になります。main.phpの読み込みには成功しますが、main.phpの内のrequire './sub.php'
でエラーが発生します。
これは実行されたスクリプトがadd.phpなので、カレントディレクトリはapp/src/dir/になります。
main.php内のrequire './sub.php'
は実際にはこのような構成を期待します
app/
src/
- main.php
dir/
- add.php
- sub.php # sub.phpがこの位置にいることを期待
このように相対PATHが起点とするカレントディレクトリは実行されたスクリプトの位置によって決まるため、思わぬバグを引き起こす可能性があります。
ちなみにこの例では以下のようにするとエラーが発生しません
絶対PATHを使用する
rootから見たsub.phpの位置をフルPATHで指定します。
この方法が一番確実です.
// main.php
require __DIR__ . '/sub.php'
PATHの書き方を変える
この方法は挙動が複雑で、お勧めしません。
// main.php
require 'sub.php'
PHPは以下のような順序で探索を行います。
- 1 インクルードパス
- 2 カレントディレクトリ(実行ファイルのディレクトリ)
- 3 その親ディレクトリをrootにたどり着くまで順に探索
ポイントはカレントディレクトリはapp/src/dir/addですので、変わらずdir/配下にsub.phpがあることを期待しますが、存在しなかった場合、親ディレクトリを探索、そこでも見つけられない場合は、更に親ディレクトリを探索するという挙動です。
localhost:8080/dir/add.phpを開いた時、結果的に以下のような状態になります。
app/
src/
- main.php
- sub.php # カレントディレクトリに存在しない場合この位置で探索にヒット
dir/
- add.php
- sub.php # main.phpのrequireはsub.phpがこの位置にいることを期待
dir2/
- sub.php # この位置は探索しない
hoge/
- sub.php # この位置は探索しない
大分複雑ですね。
このような問題を抱えてしまうため、絶対PATHを使用するのが良いと思います。
終わりに
モダンな開発で使われるフレームワークでは、相対PATHで記述しても、上記のような問題が発生しないような仕組みが備わっています。 先人に感謝を
そして、フレームワークを使う時に相対PATHで書くこともあると思いますが、このような前提を体験すると、絶対PATHで統一したくなっちゃいますね。
フレームワークを使わない開発を体験してみて、大きな発見でした。