質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.36%

php 指定したフォルダ内のファイルを全て読み込んでくれるメソッド

解決済

回答 5

投稿

  • 評価
  • クリップ 4
  • VIEW 9,948

earnest_gay

score 403

WEBページを制作する際に外部ソースの読み込みはできるだけまとめたいです。

例えば、phpで複数のクラスを定義しているファイルが「test」フォルダ内の「class」というディレクトリにあるとします。

また、「test」フォルダには
img←フォルダ
css←フォルダ
java←フォルダ
class←フォルダ
login.php
home.php
archive.php
logout.php
setting.php
等の主要ページがあります。

サイト制作するにあたり部品化(class)を作ることはよくあると思います。

私の場合はその部品は「class」フォルダに入れて

require('部品A');
require('部品B');
require('部品C');
require('部品D');
require('部品E');
というようにsetting.phpで呼び出して

require('setting.php');
というように最終的にはhome.phpやlogin.phpで呼び出してます。

これは主要ページでの呼び出す記述が一回で済むからです。

しかし、作る部品が多くなるにつれ、
setting.phpに記述するrequireも増えていくのでこれをなんとかしたいです。

例えば、指定したフォルダの中のファイルをすべて呼び出すメソッドなどはないのでしょうか?

それがあればわざわざsetting.phpを間に入れる必要もなくsetting.phpに記述するrequireもなくなり、
作った部品は「class」フォルダに入れるだけで勝手に読み込んでくれるので大変便利だと思います。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+8

全て呼び出すのは効率が悪いので,必要なときに必要なファイルだけ自動で呼び出すという仕組みが,PHPに用意されています.

// 例
spl_autoload_register(function ($classname) {
    $path = __DIR__ . '/' . $classname . '.php';
    if (file_exists($path)) {
        require $path;
    }
});

これをベースに更に規約を設けて,オートローディングのための関数すら自分で書く必要を無くした仕組みを導入したものが,PHPのパッケージマネージャ「Composer」として用意されています.PSR-4という規約(あるいは旧式のPSR-0)に則ってクラスを作成およびファイルを配置すれば,PHPが提供しているspl_autoload_registerという関数を利用して自動的に読み込みを行ってくれます.

この仕組みは,他者が提供しているライブラリをcomposer installでインストールした場合だけでなく,自分のプロジェクト内のファイルに対しても適用が可能です.composer installあるいはcomposer updateのタイミングで,自分のプロジェクト内の各クラスに対するオートローダが定義されます.

なお大前提として,ディレクトリ構成からして変えたほうがいいかと思います.HTTPでアクセスする必要のないファイルは公開ディレクトリの外に起きましょう.例えば以下の例ではwwwを公開ディレクトリとし,http://example.com/archive.phpproject/www/archive.phpに対応することを想定しています.

project
|--.git
|--composer.json
|--vendor
|  `--autoload.php
|--class
|  |--controller
|  |--model
|  `--view
`--www
   |--css
   |--img
   |--js
   |--archive.php
   |--home.php
   |--login.php
   `--setting.php

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/09 22:12

    spl_autoload_registerは便利だと聞きますが
    使い方が分からずです...

    返事遅れてすみません!
    時間があるときに具体的な内容でまたこちらで質問してみますので
    もしよろしければお願いします。

    これはまだ解決していないのでこのままにしておきます。

    キャンセル

  • 2016/06/09 22:23

    大雑把に言うと

    PHPがまだ読み込んでないクラスを使おうとする

    spl_autoload_registerで登録した関数が呼び出されるので,第1引数に渡されてきたクラス名を表す文字列をもとにrequireを行う

    エラーを回避できる (上でrequireしなければエラーになる)

    という流れになります.

    キャンセル

+1

glob()関数でファイルリストを取ってきて、1つずつrequireすれば、できることはできます(StackOverflow)。

foreach (glob("path/to/*.php") as $filename)
{
    irequire $filename;
}

ただし、このようなやり方でPHPファイルを読み込んだ場合、攻撃者からすると、取ってくる場所にPHPファイルを置くことができれば自動的に実行されるようになりますので、セキュリティ面では危険性があるかもしれません(もちろん、実稼働に際してファイルを置かれないのが大前提ではありますが)。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/09 22:10

    セキュリティー面では脆弱性があるのですね...
    my_sql_autolooderというのがあるみたいなんですが使い方が分からず...

    キャンセル

checkベストアンサー

0

こんにちは。
書き方は下記のような形になります。
_CLASS_DIRはdefineで設定しております。

//----------------------------------------------------
// クラスファイルの読み込み
//----------------------------------------------------
function autoloader($className){
require_once _CLASS_DIR . $className . ".php";
}
spl_autoload_register("autoloader");

?>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/09 23:07 編集

    なるほど!
    setting.phpで何回もrequireやっていることを
    autoloaderは自動でやってくれるのですね!

    読み込んでようがなかろうが、最終的にはautoloaderが拾ってくれるってことですよね。

    また疑問が浮かんできたのですがベストアンサーまでお付き合いいただければと思います。

    「testフォルダ」
    |index.php
    |login.php
    |logout.php

    |ー「classフォルダ」
      |
      |ー「checkフォルダ」
      |name.php
      |email.php
      |password.php
      |loader.php
      |
      |ー「getフォルダ」
      |birthday.php
      |pref.php
      |sex.php
      |loader.php

    パッと作ったので分かりやすくはないと思いますが、
    クラスをフォルダ毎に分類していた場合は
    各フォルダにloader.phpを用意してないといけないですよね?

    この場合、index.phpでloader.phpを読み込むには
    require('class/check/loader.php');
    require('class/get/loader.php');
    ってなりますよね。

    できれば1回のrequiredで
    「checkフォルダ」のクラスも
    「getフォルダ」のクラスも
    読み込みたいのですが
    それは不可能でしょうか?

    「getフォルダ」のloader.phpが「checkフォルダ」のクラスも読みに行くわけは...
    ないですよね?💦

    キャンセル

  • 2016/06/09 23:26

    誤字

    キャンセル

  • 2016/06/10 19:53

    今普通の使い方で試してみたのですが全然読み込めないです...

    Use of undefined constant _CLASS_DIR - assumed '_CLASS_DIR'


    キャンセル

0

setting.phpがindex.phpやlogin.phpと同じ階層にあると仮定します。
setting.php内に以下のコードを記述して下さい。
そして、各index.phpやlogin.php内でsetting.phpを読み込んで下さい。

$scan_dirsに自動で読み込ませたいフォルダを配列で渡しています。
以下コードはPHP5.4以上で動作します。

spl_autoload_register(function ($class_name) {
    $scan_dirs = [
        __dir__.'/class/check',
        __dir__.'/class/get',
    ];
    foreach ($scan_dirs as $scan_dir) {
        $include_path = $scan_dir.'/'.$class_name.'.php';
        if (is_readable($include_path)) {
            require_once $include_path;
            break;
        }
    }
});

新たに読み込むディレクトリを増やしたい場合は、以下のように配列に追加すれば良いです。

spl_autoload_register(function ($class_name) {
    $scan_dirs = [
        __dir__.'/class/check',
        __dir__.'/class/get',
        // ↓新しく3つの読み込むディレクトリを増やす
        __dir__.'/class/newdir1',
        __dir__.'/class/newdir2',
        __dir__.'/class/newdir3',
    ];
    foreach ($scan_dirs as $scan_dir) {
        $include_path = $scan_dir.'/'.$class_name.'.php';
        if (is_readable($include_path)) {
            require_once $include_path;
            break;
        }
    }
});

【イメージ】
// インスタンス化
$user = new User();
↑Userクラスがまだ読み込まれていない場合は、通常エラーが発生しますが、オートロード設定をしていると、以下の様な流れになります。

// ↓Userが引数として渡される
spl_autoload_register(function ('User') {
// ↓以下のようなイメージ
    foreach ($scan_dirs as $scan_dir) {
        $include_path = $scan_dir.'/User.php';
        if (is_readable($include_path)) {
            require_once $include_path;
            break;
        }
    }

わかりにくい説明ですが、このような流れです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/10 20:02

    下記のディレクトリ構成で試しましたが読み込めないです...


    「testフォルダ」
    |index.php
    |lead.php
    |ー「classフォルダ」
      |
      |ー「test1フォルダ」
      | |test1.php
      | 
      |ー「test2フォルダ」
        |test2.php
        

    【index.php】
    <?php
    require('lead.php');
    echo test1::method1;
    echo test2::method2;
    ?>


    【lead.php】
    <?php
    spl_autoload_register(function ($class_name) {
    $scan_dirs = [
    __dir__.'class/test1',
    __dir__.'class/test2',
    ];
    foreach ($scan_dirs as $scan_dir) {
    $include_path = $scan_dir.'/'.$class_name.'.php';
    if (is_readable($include_path)) {
    require_once $include_path;
    break;
    }
    }
    });
    ?>


    【test1.php】
    <?php
    class test1{
    function method1(){
    $test1 = "test1読み込めました";
    return $test1;
    }
    }
    ?>


    【test2.php】
    <?php
    class test2{
    function method2(){
    $test2 = "test2読み込めました";
    return $test2;
    }
    }
    ?>

    キャンセル

0

上記のrentoさんのコードで間違っている箇所は4箇所あります。

// lead.php

// 間違い1カ所目(一部抜粋)
__dir__.'class/test1',
__dir__.'class/test2',

// 正しくは
__dir__.'/class/test1',
__dir__.'/class/test2',

// index.php

// 間違い2カ所目
echo test1::method1;
echo test2::method2;

// 正しくは
echo test1::method1();
echo test2::method2();

// test1.php

// 間違い3カ所目
class test1{
    function method1(){
        $test1 = "test1読み込めました";
        return $test1;
    }
}

// 正しくは
class test1
{
    public static function method1()
    {
        $test1 = "test1読み込めました";
        return $test1;
    }
}

// test2.php

// 間違い4カ所目
class test2{
    function method2(){
        $test2 = "test2読み込めました";
        return $test2;
    }
}

// 正しくは
class test2
{
    public static function method2()
    {
        $test2 = "test2読み込めました";
        return $test2;
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/11 04:31

    おおお!ありがとうございます!

    methodで()つけてませんでしたね...

    時間あるときに試してみます!

    キャンセル

  • 2016/06/11 08:04

    できました!
    ありがとうございます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.36%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る