ホームページ  >  記事  >  バックエンド開発  >  PHPの自動ローディング機能を詳しく解説

PHPの自動ローディング機能を詳しく解説

零到壹度
零到壹度オリジナル
2018-03-27 10:37:311629ブラウズ

この記事は、PHP の自動ロード機能についてまとめたもので、PHP の自動ロード機能、PHP の名前空間、PHP の PSR0 および PSR4 標準などについて説明します。

1. PHP自動ローディング機能

PHP自動ローディング機能の起源

PHPの開発過程において、外部からクラスを導入したい場合、通常はinclude メソッドと require メソッドを使用して、このクラスを定義するファイルをインクルードします。小規模に開発する場合には大きな問題はありません。ただし、大規模な開発プロジェクトでは、この方法を使用するといくつかの隠れた問題が発生します。PHP ファイルで他の多くのクラスを使用する必要がある場合、多くの require/include ステートメントが必要になり、不必要なクラス ファイルの欠落や組み込みが発生する可能性があります。 。多数のファイルで他のクラスの使用が必要な場合、各ファイルに正しいクラス ファイルが含まれていることを確認するのは悪夢のような作業になり、require_once はコストが高くなります。

PHP5 は、クラスの自動読み込み (オートロード) メカニズムというこの問題の解決策を提供します。オートロード機構により、PHP プログラムは最初からすべてのクラス ファイルを組み込むのではなく、クラスが使用される場合にのみクラス ファイルを自動的に組み込むことができます。この機構は遅延ロードとも呼ばれます。

要約すると、自動ロード機能にはいくつかの利点があります:

  1. クラスを使用する前に include または require する必要はありません

  2. require/include ファイルは以下の場合にのみ実装されます。クラスを使用すると、冗長なファイルの要求/組み込みを回避できます。

  3. 導入クラスの実際のディスクアドレスを考慮する必要がなく、論理ファイルと物理ファイルの分離が実現されます。


オートロード機能について詳しく知りたい場合は、
PHPのクラス自動ロード機構
PHPのオートロード機構の実装分析

をご覧ください。

PHP 自動ロード関数 __autoload()

通常、PHP5 がクラスを使用するとき、クラスがロードされていないことが判明すると、この関数は自動的に _autoload() 関数を実行します。プログラム はい、この関数では、使用する必要のあるクラスをロードできます。以下に簡単な例を示します:

<span style="font-size: 16px;">function __autoload($classname) {  <br>  require_once ($classname . "class.php"); <br>}<br></span>

この簡単な例では、拡張子「.class.php」が付いたクラス名を直接追加してクラス ファイル名を形成し、require_once を使用してそれをロードします。この例から、autoload は少なくとも 3 つのことを行う必要があることがわかります。

  1. クラス名に基づいてクラス ファイル名を決定する。

  2. クラス ファイルが存在するディスク パスを決定する。配置されます (この例では最も単純なケースで、クラスはそれらを呼び出す PHP プログラム ファイルと同じフォルダーにあります)。

  3. クラスをディスク ファイルからシステムにロードします。

3 番目のステップは最も簡単で、include/require を使用するだけです。第 1 ステップと第 2 ステップの機能を実現するには、クラス名とディスク ファイル間のマッピング方法を開発時に合意する必要があります。この方法でのみ、クラス名に基づいて対応するディスク ファイルを見つけることができます。

インクルードするクラスファイルが多数ある場合は、対応するルールを決定するだけでよく、__autoload() 関数でクラス名と実際のディスクファイルを一致させて遅延読み込み効果を実現します。 。ここから、_autoload() 関数の実装で最も重要なことは、クラス名と実際のディスク ファイルの間のマッピング ルールの実装であることもわかります。

__autoload() 関数の問題

システムの実装で他の多くのクラス ライブラリを使用する必要がある場合、これらのクラス ライブラリは異なる開発者によって作成されている可能性があり、それらのクラス名は実際のクラス ライブラリとは異なります。ディスク ファイルのマッピング ルールが異なります。現時点で、クラス ライブラリ ファイルの自動ロードを実装したい場合は、すべてのマッピング ルールを __autoload() 関数に実装する必要があります。この場合、autoload() 関数は非常に複雑になるか、実装が不可能になる可能性があります。最終的に、autoload() 関数は実装できたとしても非常に肥大化する可能性があり、将来のメンテナンスとシステム効率に大きな悪影響を及ぼします。

それでは、どこに問題があるのでしょうか?問題は、_autoload() が 1 回しか定義できないグローバル関数であり、柔軟性が十分ではないため、クラス名とファイル名に対応するすべての論理ルールを 1 つの関数で実装する必要があり、この関数が肥大化してしまうことです。では、この問題をどうやって解決すればいいのでしょうか?答えは、_autoload コール スタックを使用し、異なるマッピング関係を異なる _autoload 関数に書き込み、それらを均一に登録して管理することです。これが PHP5 で導入された SPL オートロードです。

SPL Autoload

SPLとは、Standard PHP Libraryの略称です。これは、PHP5 で導入された拡張ライブラリであり、その主な機能には、オートロード メカニズムとさまざまな Iterator インターフェイスまたはクラスの実装が含まれます。 SPL Autoload にはいくつかの固有の関数があります:

  1. spl_autoload_register: __autoload() 関数を登録します。

  2. spl_autoload_unregister: 登録された関数を登録解除します

  3. pl_autoload_functions: 登録されているすべての関数を返します

  4. spl_autoload_call: 登録されているすべての関数を試してクラスをロードします

  5. spl_autoload : __autoload() のデフォルト実装

  6. spl_autoload_extions: spl_autoload で使用されるデフォルトのファイル拡張子を登録して返します機能。


これらの関数の詳しい使い方は、php

のspl_autoloadの詳しい説明にあります。簡単に言えば、spl_autoloadはSPL独自に定義された__autoload()関数です。関数は非常に簡単で、登録されたディレクトリ (set_include_path 設定) $classname と同じ名前の .php/.inc ファイルを見つけます。もちろん、拡張子 (spl_autoload_exions) を登録することで、特定の種類のファイルを指定することもできます。

spl_autoload_register() は、上で説明した自動ロード呼び出しスタックです。PHP がクラス名を見つけられない場合、この関数に複数の独自の _autoload() 関数を登録できます。PHP はこのスタックを呼び出し、カスタム _autoload を呼び出します。 () 関数を 1 つずつ実行して自動ロード機能を実現します。この関数にパラメータを入力しない場合は、spl_autoload() 関数が登録されます。

さて、これは PHP 自動読み込みの最下層です。登録メカニズムはすでに非常に柔軟ですが、何が欠けているのでしょうか?上で述べたように、自動読み込みの鍵となるのは、クラス名とファイルのマッピングです。このマッピング関係はフレームワークごとに異なりますが、柔軟性が高すぎると、PHP が特殊なように見えます。このマッピング関係の仕様は、標準では PSR PSR0 および PSR4 です。

しかし、PSR0 と PSR4 について話す前に、PHP の名前空間の問題についても理解する必要があります。これら 2 つの標準は、実際にはクラス名とディレクトリ ファイルのマッピングではなく、名前空間とファイルのマッピングを目的としているためです。なぜそうなるのでしょうか?私の理解では、標準的なオブジェクト指向 PHP の考え方では、名前空間はある程度クラス名のエイリアスです。では、なぜ名前空間を導入する必要があるのでしょうか。また、名前空間の利点は何でしょうか? 2.名前空間

名前空間を理解するには、まず公式ドキュメントの名前空間の概要を見てください:

名前空間とは何ですか?大まかに言えば、名前空間は物事をカプセル化する方法です。この抽象的な概念はさまざまな場所で見られます。たとえば、ディレクトリはオペレーティング システムで関連ファイルをグループ化するために使用され、ディレクトリ内のファイルの名前空間として機能します。たとえば、ファイル foo.txt はディレクトリ /home/greg と /home/other に同時に存在できますが、2 つの foo.txt ファイルが同じディレクトリに存在することはできません。さらに、ディレクトリ /home/greg の外にある foo.txt ファイルにアクセスする場合、/home/greg/foo.txt を取得するには、ファイル名の前にディレクトリ名とディレクトリ区切り文字を置く必要があります。この原則をプログラミングの分野に適用したのが、名前空間の概念です。
PHP では、クラス ライブラリやアプリケーションを作成するときに、クラスや関数などの再利用可能なコードを作成するときに発生する 2 種類の問題を解決するために名前空間が使用されます:
1 ユーザーが作成したコードと PHP 内部のクラス/関数/定数、または 3 番目のコード間の名前の競合パーティ クラス/関数/定数
2 非常に長い識別子名の (または短い) 名前を作成し (通常、最初の種類の問題を軽減するために定義されます)、ソース コードの読みやすさを向上させます。
PHP 名前空間は、関連するクラス、関数、定数をグループ化する方法を提供します。


簡単に言うと、PHPではプログラム内で同じ名前のクラス、関数、変数名を2つ使用することができないので、同じでなくても大丈夫という人もいるのではないだろうか。名前?実際、大規模なプログラムの多くは多くのサードパーティ ライブラリに依存しています。これは、公式 Web サイトの最初の問題ではありません。では、この問題をどうやって解決すればいいのでしょうか?名前空間がない場合、下手なプログラマはクラス名 a_b_c_d_e_f しか付けることができません。ここで、a/b/c/d/e/f には通常、独自の特定の意味があり、競合は起こりませんが、この長いクラス名は書くのは疲れるし、読むのはさらに不快です。したがって、PHP5 では、クラス名がクラス名であり、名前空間がプログラムの書き込み/読み取り時に、マシンが名前空間を参照するようになりました。これにより、問題が解決されました。

さらに、名前空間は、関連するクラス、関数、定数をグループ化する方法を提供します。これは、オブジェクト指向言語の名前空間の優れた使い方でもあり、特定の目的に必要なクラス、変数、関数は名前空間に書き込まれ、カプセル化されます。

クラス名の問題は解決され、ついに PSR 標準に戻ることができるようになりました。では、PSR0 と PSR4 はファイルと名前空間の間のマッピング関係をどのように標準化するのでしょうか?答えは、名前空間の命名 (少しわかりにくいですが)、クラス ファイル ディレクトリの場所、および 2 つの間のマッピング関係に関する制限です。これが標準の中核です。より完全な説明は、モダン PHP 新機能シリーズ (1) - 名前空間

3. PSR 標準

を参照してください。

PSR0 と PSR4 について話す前に、PSR 規格を紹介しましょう。 PSR 標準の発明者および標準化者は PHP-FIG で、その Web サイトは www.php-fig.org です。 PSR 仕様を考案し、作成したのはこのコンソーシアムです。 FIG は、Framework Interoperability Group の略称で、2009 年に数人のオープンソース フレームワーク開発者によって設立されました。それ以来、他の多くのメンバーが選ばれていますが、コミュニティの大部分を代表しています。 。この組織の目的は、各プロジェクトのコーディング標準を最小限の制限で統一し、各社独自の開発スタイルがプログラム設計者の発展を妨げることを回避することです。 そこで皆で考案し、まとめたのが標準規格の提案です。 (標準提案の提案)Standard Proposalの略)。

特定の詳細な仕様を参照できます
PHPによるPSR仕様

PSR0標準

PRS-0仕様は、主にいくつかの自動読み込み標準を策定するために発行された最初の仕様セットです(オートローディング標準) PSR-0 必須要件:

1. 完全修飾された名前空間とクラスは、次の構造に準拠する必要があります: "()*"
2.各名前空間にはトップレベルの名前空間 (「ベンダー名」プロバイダー名) が必要です
3. 各名前空間は複数のサブ名前空間を持つことができます
4. ファイル システムからロードする場合、各名前空間の区切り文字 (/) は次のように変換される必要があります。 DIRECTORY_SEPARATOR (オペレーティング システムのパス区切り文字)
5. クラス名内の各アンダースコア (_) 記号は DIRECTORY_SEPARATOR (オペレーティング システムのパス区切り文字) に変換される必要があります。名前空間内では、underscore_ 記号には (特別な) 意味はありません。
6. ファイル システムからロードする場合、修飾された名前空間とクラスは .php で終わる必要があります。
7. Verdor 名、名前空間、クラス名は大文字と小文字で構成できます (大文字と小文字は区別されます)


具体的なルールは少しわかりにくいかもしれないので、最初から始めましょう。

まず、PSR0 標準の一般的な内容を見てみましょう。第 1 条、第 2 条、第 3 条、および第 7 条は、名前空間の名前を制限し、第 4 条と第 5 条は、名前空間とファイル ディレクトリの 6 つの項目の間のマッピング関係を制限します。はファイル拡張子です。

前に述べたように、PSR 標準は、名前空間とそれが配置されているファイル ディレクトリの間のマッピング関係をどのように標準化するのでしょうか?これは、ネームスペースの名前、ファイル ディレクトリの場所、およびそれら 2 つの間のマッピング関係を制限することによって行われます。

では、ファイルが置かれているディレクトリの場所の制限はどこにあるのか、ということになるかもしれません。実際、答えは次のとおりです。

制限された名前空間名 + 制限された名前空間名とファイルディレクトリのマッピング = 制限されたファイルディレクトリ

それでは、まず考えてみましょう。特定のプログラムについて、PSR0 標準をサポートしたい場合、どのような調整が必要ですか。 ?

  1. まず、プログラムは PSR0 標準の第 4 条と第 5 条に準拠するマッピング関数を定義し、次にこの関数を spl_register() に登録する必要があります。次に、新しい名前空間を定義します。 、名前空間の名前とファイルのディレクトリの場所は、第 1 条、第 2 条、第 3 条、および第 7 条に準拠する必要があります。

  2. 通常、コードメンテナンスの便宜上、ファイル内には名前空間を 1 つだけ定義します。

    さて、PSR0 に準拠した名前空間の名前がわかりました。PSR0 規格に準拠したマッピング関係を通じて、ファイルを正しく保存すれば、PSR0 規格に準拠したファイル ディレクトリ アドレスを取得できます。 PSR0 標準では、ファイルを正常に要求でき、この名前空間を使用できます。すごいですね。
次に、PSR0 標準の仕様を詳しく見てみましょう。

上記の PSR0 標準について説明するために、laravel のサードパーティ ライブラリ Symfony の名前空間の 1 つ /Symfony/Core/Request を例に挙げてみましょう。






完全修飾された名前空間とクラスは、次の構造に準拠する必要があります: "52f0a8d2734c4b535654453e49349ac9(1db0f77747bb2a800b935b09d3ea2286)*f4e9db28b9ff9ba3f3e4b75ebb041388"

  1. 上記 /Symfonyはベンダー名で、これはサードパーティのライブラリの名前です。 /Core は名前空間名で、通常は名前空間の属性情報です (たとえば、request は Symfony のコア関数です)。名前空間の名前、これ 標準仕様では、名前空間のソースと機能が非常に明確に見えるようになっており、これはコードのメンテナンスに役立ちます。

2. 各名前空間にはトップレベルの名前空間(「ベンダー名」プロバイダー名)が必要です

つまり、各名前空間には /Symfony に似たトップレベルの名前空間が必要です。なぜそのようなルールがあるのでしょうか? PSR0 標準は、トップレベルの名前空間、つまり /Symfony/Core/Request の部分以降のマッピング関係のみを担当するため、/Symfony をどのディレクトリに関連付ける必要があるかは、ユーザーまたはフレームワーク自体によって定義されます。いわゆるトップレベルの名前空間は、カスタマイズされたマッピング関係を持つ名前空間であり、通常はプロバイダー名 (サードパーティ ライブラリの名前) です。言い換えれば、トップレベルの名前空間は自動ロードの基礎となります。なぜこのように基準が定められているのでしょうか?理由は非常に簡単です。名前空間 /Symfony/Core/Transport/Request があり、別の名前空間が /Symfony/Core/Transport/Request1 である場合、トップレベルの名前空間がない場合、2 つのパスを記述する必要があります。名前空間に対応して、Request2とRequest3がある場合はどうなるでしょうか。最上位の名前空間 /Symfony を使用すると、それに対応するディレクトリのみが必要になり、残りは PSR 標準を使用して解析できます。

3. 各名前空間は複数のサブ名前空間を持つことができます

リクエストは/Symfony/Core/Request または /Symfony/Core/Transport/Request として定義できます。 Core 名前空間の下に多数のサブ名前空間を含め、そこに含める名前空間の層の数を定義できます。

4. ファイルシステムからロードする場合、各名前空間の区切り文字(/)はDIRECTORY_SEPARATOR(オペレーティングシステムのパス区切り文字)に変換されます

さて、いよいよマッピングの標準化です。ネームスペースの / 記号はパス区切り文字に変換する必要があります。これは、ネームスペース /Symfony/Core/Request を SymfonyCoreRequest などのディレクトリ構造に変換する必要があることを意味します。

5. クラス名内の各アンダースコア _ 記号は DIRECTORYSEPARATOR (オペレーティング システムのパス区切り文字) に変換する必要があります。名前空間では、アンダースコア記号には (特別な) 意味はありません。

この文の意味は、名前空間が /Symfony/Core/Request_a の場合、それを SymfonyCoreRequesta のようなディレクトリにマップする必要があるということです。なぜそのような規定があるのでしょうか?これは、PHP5 より前には名前空間がなく、プログラマーは Symfony_Core_Request_a という名前しか付けられなかったためであり、PSR0 のこの規定はこの状況に対応するためのものです。
残りの 2 つは非常に簡単なので、詳細は説明しません。

このような名前空間の命名規則とマッピング標準を使用すると、名前空間が配置されている場所にファイルを配置する必要があるかを推測できます。引き続き Symfony/Core/Request を例にとると、そのディレクトリは /path/to/project/vendor/Symfony/Core/Request.php です。ここで、/path/to/project はディスク上のプロジェクトの場所、/path です。 /to /project/vendor は、プロジェクトで使用されるすべてのサードパーティ ライブラリが配置されるディレクトリです。 /path/to/project/vendor/Symfony は、トップレベルの名前空間/Symfony に対応するディレクトリです。以下のファイル ディレクトリは PSR0 標準に従って確立されます。

/Symfony/Core/Request => /Symfony/Core/Request.php

すべてが完璧ですよね?いいえ、まだいくつかの欠陥があります:

  1. 名前空間なしでも互換性を維持する必要がありますか?

  2. PSR0規格によれば、ネームスペース/A/B/C/D/E/Fはディレクトリ構造/A/B/C/D/E/Fに対応する必要があります。階層が深い?

PSR4規格

2013年末に、5番目の仕様であるPSR-4がリリースされました。

PSR-4 は、クラス定義を自動的にロードするためのファイルパスの指定方法を標準化し、自動ロードされるファイルの場所も標準化します。一見すると、これは PSR-0 に似ていますが、実際には機能的に重複する部分があります。違いは、PSR-4 仕様が比較的クリーンで、PHP 5.3 の以前のバージョンと互換性のあるコンテンツが削除されており、PSR-0 のアップグレード バージョンのように感じられることです。もちろん、PSR-4 は PSR-0 を完全に置き換えることを目的としたものではなく、必要に応じて PSR-0 を補足することを目的としています。もちろん、必要に応じて PSR-4 を PSR-0 と置き換えることもできます。 PSR-4 は、PSR-0 を含む他の自動ロード メカニズムと一緒に使用できます。

PSR4 標準と PSR0 標準の違い:

  1. 在类名中使用下划线没有任何特殊含义。

  2. 命名空间与文件目录的映射方法有所调整。

对第二项我们详细解释一下 ( Composer自动加载的原理):
假如我们有一个命名空间:Foo/class,Foo 是顶级命名空间,其存在着用户定义的与目录的映射关系:

<span style="font-size: 16px;">"Foo/" => "src/"<br/></span>

按照PSR0标准,映射后的文件目录是: src/Foo/class.php,但是按照 PSR4 标准,映射后的文件目录就会是:src/class.php,为什么要这么更改呢?原因就是怕命名空间太长导致目录层次太深,使得命名空间和文件目录的映射关系更加灵活。

再举一个例子,来源 PSR-4——新鲜出炉的PHP规范:
PSR-0风格

<span style="font-size: 16px;">    vendor/<br>    vendor_name/<br>        package_name/<br>            src/<br>                Vendor_Name/<br>                    Package_Name/<br>                        ClassName.php       # Vendor_Name\Package_Name\ClassName<br>            tests/<br>                Vendor_Name/<br>                    Package_Name/<br>                        ClassNameTest.php   # Vendor_Name\Package_Name\ClassName<br></span>

  PSR-4风格

<span style="font-size: 16px;">    vendor/<br>    vendor_name/<br>        package_name/<br>            src/<br>                ClassName.php       # Vendor_Name\Package_Name\ClassName<br>            tests/<br>                ClassNameTest.php   # Vendor_Name\Package_Name\ClassNameTest<br></span>

对比以上两种结构,明显可以看出PSR-4带来更简洁的文件结构。

以上がPHPの自動ローディング機能を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。