[PHP] requireは__DIR__から書けくベシ!

PHP
プログラミングを仕事にしている人は、もしかすると同じ様な経験をしたことがある人が多いと思うんですが、 依頼されて作ったプログラムが完成したあとで、「やっぱりここ変更して」とお気軽に言われてしまう事ありませんか? 要件定義に沿って行ったにも関わらず、「やっぱり仕様変更します」と軽く言われると、 友達や恋人から、美味しいものを食べている時に「あ〜んして」と言われて、口を顔の半分ぐらい大きく広げた瞬間に、相手がそのスプーンを自分の口に放り込んで、「な〜んちゃって」といっちゃう、あの仕草と同じぐらい腹立たしく感じてしまうことがあります。 ※これ、名称があるのかな?「やっぱり、あ〜げない!」みたいな可愛気のある名称ではなく、「相手を失意に落とし込む悪気の有りまくる食べ物詐欺」とでも言いましょうか・・・ とにかく、プログラミングが出来るできないって、非常に大きな思考の格差があるため、こうした事態は実は当たり前のように起きています。 そう、毎朝パンにバターを塗るぐらい当たり前のように・・・ 今回は、PHPを使った作業で、自分の書いたコードでエラーが出たことから、戒めのために、ブログに書き残しておくことにします。

PHPのrequireについての話

PHPで作ったシステムで、他のディレクトリから、ライブラリとしてある一部分を参照しようと思った時に、エラーがでてしまいました。 もともと、単体で使うだけのシステムだったんですが、思いの外便利なツールが出来上がったので、それを別のシステムからも参照したいとの要望変更が発生したタイミングで発覚しました。 原因は簡単なモノで、PHPのライブラリファイルの読み込みで、require_once命令を使いますが、これが、ライブラリ内で使われていて、そのライブラリからの相対パスで記述されていた為です。 わかりやすくサンプルを書いてみました。

コードサンプル

<?php require_once './A_2.php'; <?php echo 'A-2'; <?php require_once '../A/A_1.php';

A/A_1.phpを実行

これを実行すると、画面に「A-2」と表示されます。 同一階層で、A_2.phpを呼び出して正常に動作していることが確認できます。

B/B.phpを実行

Warning: require_once(./A_2.php): Failed to open stream: No such file or directory in /~~/A/A_1.php on line 3 Fatal error: Uncaught Error: Failed opening required './A_2.php' (include_path='.:/usr/local/lib/php') in /~~/A/A_1.php:3 Stack trace: #0 /~~/B/B.php(3): require_once() #1 {main} thrown in /~~/A/A_1.php on line 3
上記のようなエラーが画面に表示されてしまいます。 "./A_2.php" こんなファイルありませんで!と言われているようです。

解決方法

このエラーを解決するには、"./A_2.php"の箇所を、"A_2.php"とすると簡易には解決します。 または、root階層からの記述にすることでも、確実にエラー回避はできます。 "/~~/A/A_2.php" この絶対パスが確実なため、マジック定数の__DIR__を使うのが良いでしょう。

マジック定数 : __DIR__

__DIR__には、この環境の場合は、A_1.phpで実行した場合、"/~~/A/"という上位の絶対パスが入ります。 という事で、次のように書くことで完璧版となります。 <?php require_once __DIR__ . '/A_2.php'; 注意点としては、__DIR__は上位フォルダですが、最後が"/"で終わっていない文字列になっているという事を認識しておきましょう。 なので、その後に続く文字列は、"/"(スラッシュ)から始めましょうね。

他の書き方を覚えて周辺知識をつけよう!

__DIR__というのがマジック定数というのが理解できた人は、PHPのマジック定数には、他にどんなモノがあるか知っておきましょう。 https://www.php.net/manual/ja/language.constants.magic.php このページに一覧が載っているので、見るだけで理解できると思います。 興味深いのは、__DIR__は、他にもdirname(__FILE__)という書き方も出来るという点ですね。 今回の件とは別の視点になりますが、PHPには、requireの他にもincludeという命令もあり、どちらもPHPファイルを読み込む動作をします。 この2つの違いって一体何が違うんでしょう?

PHPのincludeとrequireの違い

https://webukatu.com/wordpress/blog/31768/#require このページに答えが書かれていました。 違いは、存在しないファイルを読み込んだ時にどう振る舞うかの違いだったようです。
・include:includeの処理部分は停止されるが、その後の処理は実行される ・require:その場でエラーになり、その後の処理も停止される
エラーが出てくれたほうが、修正もできるし不具合を含んだまま使わずに済むことになるので、requireが好まれて使われているんでしょうね。

あとがき

なにはともあれ、仕事でエラーが出た時に、このぐらいスマートに対応できれば、リカバリーも早く済むということですが、 requireのパスが原因だということに気が付かなければ、こんな対応で1日や2日は軽く吹っ飛んでしまうわけです。 エラー文言見れば、分かりそうなものですが、こうした経験、やったことある人とない人で、差が出てしまう事もよくわかりますね。 吹っ飛んで良いのは、ふとんだけですよ。 ふとんが、ふっt・・・