include_pathってなんやねん
PHPを使い始めてもうすぐ三か月がたちます。ようやく赤ちゃんから小学生くらいには成長したのではないかというところで、業務でドはまりしたことがありました。何がしたかったかというと、ダウンロードしてきた外部モジュールをそのまま開発環境に置いて、Controllerとかから外部モジュールを呼び出したかったわけです。でもまぁこれが思ったよりうまくいかなかったので覚書として。
状況説明
簡単にですがディレクトリ構造を再現してみました。外部モジュール内にあるphpファイルをsampleController.php
で呼び出すことが目標です。
app
├─Http
| └─Controllers
| └─sampleController.php
├─Models
└─外部モジュール
└─packageQ
├─A
| └─A.php
├─B
| └─callA.php
└─C
└─callAB.php
<?php
class A
{
public function hoge() {
echo 'Aだよ';
}
}
<?php
require_once 'packageQ/A/A.php';
class callA
{
public function hoge2() {
echo 'Bだよ';
echo 'Aを呼ぶよ';
hoge();
// Aだよ
}
}
<?php
require_once 'packageQ/A/a.php';
require_once 'packageQ/B/callA.php';
class callAB
{
public function hoge3() {
echo 'ABだよ';
echo 'A, Bを呼ぶよ';
hoge();
// Aだよ
hoge2();
// Bだよ;
// Aを呼ぶよ;
// Aだよ
}
}
タイトル回収
include_pathはいわゆるPHP内の環境変数です。include_pathはrequire
とかinclude
を使って外部のphpファイルを呼び出すときに使います。この記事がわかりやすかったので是非参考にしてください。
さて、これら外部のphpファイルを読み込むには読み込みたいファイルのpathを指定する必要があります。pathの指定は絶対パスで相対パスでもどちらでも構いません。ちなみに相対パスよりも絶対パスのほうが実効速度が速くなるらしいです。
ここではまりポイントが2つ現れます。一つずつ見ていきましょう。
dockerを使っているのに、パスの指定をPC上のパスを指定していた
dockerでlaravelを使うときapp以下をvolumesで/var/www/とかに流しておくと思います。この時include_pathは $/var/www/app/hogehoge$ という風になるはずです。なのに、私はずっとvscode上で絶対パスを取得していて、「おかしいなぁ、動かないなぁ」と考えていました。
include_pathの設定はunixとwindowsの二つがある
include_pathはphp.ini内で設定されています。laradockだとphp{version}.iniです。見出しにもあるように実行環境?がどんなos動いているかによってパスの指定が異なります。私はwindowsを使っていますが、docker内で実行するのが前提なので、パスはunixの部分を修正する必要があります。
以上2点がinclude_pathについての、はまりポイントです。
きっと初歩的な間違いなんだろうな、、、
composerのclassmap
さて、ここまでくるともうほとんどやることはcomposerさんがやってくれます。composerさんはすごくてclassmapというところに、laravel内で読み込みたいファイル or ディレクトリを書き込むと、名前空間と書き込んだファイルやディレクトリのパスを紐づけてくれます。
なので今回の場合、"外部モジュール/packageQ" とかいう感じでcomposer.jasonに書き込み、composer dump-autoloadまで行います。あとは、コントローラーで use 名前空間 で所望のphpファイルが呼び出せるということです。
どうしても、class not found になるときは autoload_classmap.php を一度確認してみるといいかもしれません。ファイルの中身は実際に見ていただくとわかるのですが、キーが名前空間で値がパスになっています。エディタの検索(vscodeだと ctrl+F)とか使ってファイル名から名前空間を探し出すといいと思います。私も今回これで切り抜けました。
追記
似たようなことを書いている人を見つけました。
コントローラーからrequireで呼び出せない?
外部モジュールをコントローラーから呼び出すのに、composerを使って名前空間を設定したのですが、別にrequireとか使ってもいいわけです。手間とか考えるとcomposerが楽だよねって話なだけで。余談ですが、私はなぜかコントローラーからはrequireで外部モジュールを呼び出せなかったです。include_pathの設定がおかしいのが原因だと思いますが、composerが楽ちんなので深くは考えないことにしました。