前の記事で、クラスを自動的にロードするにはどうすればよいかという質問をしました。
実際、PHP にはこの機能を実現するための対応するメカニズムがすでにあり、このメカニズムは autoload であり、まだ定義されていないクラスを使用しようとすると自動的に呼び出されます。
これで、Route.php の先頭で autoload 関数を定義できます (もちろん、これは標準化されていませんが、簡単にするために最初に定義しましょう)。
現在の自動インポートでは、コードを簡素化するために、フレームワークのクラス ファイルとユーザー アプリケーション モジュールのクラス ファイルの 2 種類のファイルをインポートする必要があります。フレームワークのすべてのファイルは、/Test ディレクトリの下の /Library に保存されます。ユーザー クラス ファイルは、/UserApps/Modules ディレクトリの下に保存されます。また、Controllers、Models、および Helpers の 3 つのディレクトリの下にのみ存在し、サブディレクトリはありません。これらのディレクトリの下にあります。
この自動インポート関数では、最初にフレームワーク クラス ファイルのインポートを試行する必要があります。ファイルが存在しない場合は、それがユーザー クラス ファイルであることを意味し、次にユーザー クラス ファイルのインポートを試行する必要があります。ある場合は、それを含めます。
注:
UserApps/Modules ディレクトリを頻繁に使用するため、MODULES_PATH 定数を定義しました。
01 | function __autoload($className) { |
02 | $frameworkFileName = FRAMEWORK_PATH . '/' . $className . '.php'; |
関数 __autoload($className) {
03 | if(is_file($frameworkFileName)) { |
04 | include $frameworkFileName; |
02
05 | } else { |
06 | //用户类文件 |
07 | $controllerFileName = MODULES_PATH . '/Controllers/' . $className . '.php'; |
08 | if(is_file($controllerFileName)) { |
09 | include $controllerFileName; |
10 | } else { |
11 | $modelFileName = MODULES_PATH . '/Models/' . $className . '.php'; |
12 | if(is_file($modelFileName)) { |
13 | include $modelFileName; |
14 | } else { |
15 | $helperFileName = MODULES_PATH . '/Helpers/' . $className . '.php'; |
16 | if(is_file($helperFileName)) { |
17 | include $helperFileName; |
18 | } else { |
19 | throw new Exception("class not found"); |
20 | } |
21 | } |
22 | } |
23 | } |
24 | } |
この関数の記述が完了したら、以前に記述した IndexController.php でテストできます。たとえば、IndexController と同じディレクトリにファイル Test.php を作成します。ファイルのコードは次のとおりです。
1 |
2 | class Test { |
4 | echo 'Test'; |
2
5 | } |
6 | } |
その後、IndexController.php で次のように使用します:
<テーブル>
1 |
2 | class IndexController { |
4 | $test = new Test(); |
2
5 | $test->test(); |
6 | } |
7 | } |
「テスト」が表示されたら、おめでとうございます。自動インポートは成功しました。 !
もう一度考えてみましょう。この方法を使用して非常に複雑なプロジェクトを自動的にインポートする場合、何か問題はありますか?
実は、この問題は非常に深刻です。まず、フレームワーク ファイルについては、すべてのファイルを 1 つのディレクトリに保存することができないため、ファイルが多すぎると取得するのが面倒になります。すべてのコントローラ ファイルを 1 つのディレクトリに保存することは不可能です。モジュールなどに応じてディレクトリを分割する必要があります。 __autoload を使用して実装すると、この関数のコード量が膨大になり、一か所の変更がシステム全体に影響を与える可能性があり、プロジェクトの保守に非常に悪影響を及ぼします。
では、この問題をどうやって解決すればよいでしょうか?
方法 1:
フレームワーク ファイルのインポートなどの多くの補助関数を定義し、frameworkAutoloadHelper を定義し、ユーザー ファイル用の userAutoloadHelper を定義します。次に、これら 2 つの関数にビジネス ロジックを格納し、最後にこれら 2 つを __autoload で呼び出します。関数は次のとおりです。ユーザー関数を変更する必要がある場合は、
の方が優れています。方法 2:
SPL では spl_autoload_register が定義されており、これを使用して自動インポート機能を複数のクラスに割り当てることができ、自動インポートの制御をユーザーに与えることができます。これはフレームワークにとってより重要です。 , そのため、この方法を使用することをお勧めします。
このメソッドの実装方法の詳細については、PHP マニュアルを確認してください。
spl_autoload_register を使用した後は、すべてが心配しなくなりますか?
実際にはいいえ、自動インポートを削除できるかどうかを考えます。ビジネス ロジックが複雑で、自動インポートの設計があまり優れていない場合、自動インポートの効率はあまり高くないからです。 !
自動的にインポートする必要がない場合でも、 include を使用する必要がありますか?いいえ。
include、include_once、require、require_once の違いは誰もが知っています。 !
include と require が呼び出されるたびに、このファイルはインクルードされ、require_once は 1 回だけインポートされます。 include に存在しないファイルが含まれている場合は、警告がスローされるだけで、プログラムは続行されます。実行すると、require は実行を停止します。そのため、これら 4 つの関数には require_once を使用することを好みますが、残念ながら、この関数は考慮すべき点が多すぎるため、非常に非効率的です。 !
追記: これら 4 つの関数を使用する場合は、より効率的な絶対パスを使用するのが最善です。
require を使うと効率がよくなりますが、require を使う場合、require_once 関数はどのように実装すればよいでしょうか?アイデアを提供します。静的変数を使用します:
1
1 |
2 | function testRequireOnce($file) { |
3 | static $_config = array(); |
4 | if(!isset($_config[$file])) { |
5 | require $file; |
6 | $_config[$file] = $file; |
7 | } |
8 | } |
もちろん、class_exists を使用して判断することもできます。