39

最近のほとんどのWeb開発者と同様に、私はWebアプリとサイトの堅固なMVCアーキテクチャーの利点を十分に楽しんでいます。PHPでMVCを実行する場合、自動ロードは明らかに非常に便利です。

それぞれが独自の自動ロードを使用する異なるベースモジュールを組み込んでいる場合、これは明らかにより柔軟であるため、私はspl_autoload_register単純に単一の関数を定義するのが好きになりました。__autoload()しかし、私が書いたロード関数については、これまで素晴らしいと感じたことはありません。ロードする可能性のあるクラスを探すために、多くの文字列チェックとディレクトリスキャンが必要です。

たとえば、ベースパスが、として定義され、ディレクトリが、、およびという名前の単純な構造を持つアプリがあるとしPATH_APPます。私はよくファイルに名前が付けられ、適切なディレクトリ内にあるという名前付け構造を採用しています。モデルには通常、デフォルトで特定のスキームはありません。私は次のように登録されるこの構造のローダー関数を持っているかもしれません:modelsviewscontrollersIndexView.phpIndexController.phpspl_autoload_register

public function MVCLoader($class)
{
    if (file_exists(PATH_APP.'/models/'.$class.'.php')) {
        require_once(PATH_APP.'/models/'.$class.'.php');
        return true;
    }
    else if (strpos($class,'View') !== false) {
        if (file_exists(PATH_APP.'/views/'.$class.'.php')) {
            require_once(PATH_APP.'/views/'.$class.'.php');
            return true;
        }
    }
    else if (strpos($class,'Controller') !== false) {
        if (file_exists(PATH_APP.'/controllers/'.$class.'.php')) {
            require_once(PATH_APP.'/controllers/'.$class.'.php');
            return true;
        }
    }
    return false;
}

それでも見つからない場合は、modelsディレクトリのサブディレクトリをスキャンする別の機能がある可能性があります。ただし、if / else、文字列チェック、ディレクトリスキャンはすべて私には非効率的であるように思われるので、改善したいと思います。

他の開発者が採用する可能性のあるファイルの命名と自動読み込みの戦略に非常に興味があります。私は、自動読み込みに代わるものではなく、効率的な自動読み込みに使用できる優れた手法を特に探しています。

4

3 に答える 3

29

これは私が私のすべてのプロジェクトで使用しているものです(最後のプロジェクトのソースから直接持ち上げられました):

public static function loadClass($class)
{
    $files = array(
        $class . '.php',
        str_replace('_', '/', $class) . '.php',
    );
    foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $base_path)
    {
        foreach ($files as $file)
        {
            $path = "$base_path/$file";
            if (file_exists($path) && is_readable($path))
            {
                include_once $path;
                return;
            }
        }
    }
}

SomeClass_SeperatedWith_Underscoresを検索すると、SomeClass_SeperatedWith_Underscores.phpが検索され、続いて現在のインクルードパスの各ディレクトリをルートとするSomeClass / SeperatedWith/Underscores.phpが検索されます。

編集:私はこれを開発の効率のために使用し、必ずしも処理時間ではないことを伝えたかっただけです。パスにPEARがある場合は、これを使用すると、クラスを使用するだけで、必要なときにクラスを含める必要がありません。

私はクラスをディレクトリの階層に保持する傾向があり、アンダースコアは名前空間を分割します...このコードを使用すると、必要に応じてファイル構造を整理し、必要に応じてネストされたディレクトリなしでクイッククラスファイルを挿入できます(被告であるが、現在取り組んでいるプロジェクトの一部ではないライブラリに1つまたは2つのクラスを追加します。)

于 2009-04-27T01:09:34.083 に答える
13

私はこの解決策にたどり着きました:

クラスライブラリフォルダー(個別のモジュール/システムのサブフォルダーを含む)をトラバースし、ファイルの内容を解析してクラス定義を探す単一のスクリプトを作成しました。phpファイル(非常に単純な正規表現パターン)でクラス定義が見つかると、シンボリックリンクが作成されます。

class_name.php -> actual/source/file.php

これにより、クラス名とメインのシンボリックリンクフォルダーへのパスのみを必要とし、パス/文字列の操作を行う必要がない、単一の単純な自動ロード関数を使用できます。

最良の部分は、ソースコードを完全に再配置するか、新しいサブシステムを追加して、リンク生成スクリプトを実行するだけですべてを自動ロードできることです。

于 2009-04-27T01:34:18.390 に答える
8

効率が必要な場合は、自動ロード機能をまったく使用しないでください。自動ロード機能は怠惰になるためのものです。インクルードファイルをインクルードするときは、インクルードファイルへの明示的なパスを指定する必要があります。autoload関数がこれらのファイルを見つけることができる場合は、それらを明示的に見つけるようにコーディングできます。コードのビュー部分で作業していて、新しいビュークラスをロードしようとしているとき、autoload関数にそれを処理させることにより、最初にクラスがモデルクラスであると想定しますか?それは非効率的です。代わりに、コードは次のようになります。

include_once $this->views_path . $class . '.php';

複数の「ビュー」パスが必要な場合は、ビューをロードする関数を作成します。

public function load_view($class) {
    // perhaps there's a mapping here instead....
    foreach ($this->views_paths as $path) {
        $filename = $path . $class . '.php';
        if (file_exists($filename)) {
            include_once $filename;
        }
    }
    throw ....
}

いずれの場合も、インクルードが発生した時点で、ロードするクラスに関する最大/最も正確な情報が得られます。その情報を使用してクラスを完全にロードすることが、唯一の効率的なクラスロード戦略です。はい、あなたはより多くのクラス変数または(天国は禁じられている)いくつかのグローバル変数で終わるかもしれません。しかし、それは単に怠惰でクラスのファイルシステムの一部をスキャンするよりも良いトレードオフです。

于 2009-04-27T02:12:30.937 に答える