PHPは自動ローディング機能を実装しています

小云云
リリース: 2023-03-22 13:16:01
オリジナル
5730 人が閲覧しました

この記事は主に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 auto-読み込み関数 __autoload()

通常、PHP5 がクラスを使用するときに、クラスがロードされていないことが判明すると、_autoload() 関数がプログラム内でカスタマイズされ、必要なクラスをロードできます。使用します。以下に簡単な例を示します:

<span style="font-size: 14px;">function __autoload($classname) {    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() 関数を登録できます。1 つはカスタム _autoload です。 () 関数を使用して自動ロード機能を実装します。この関数にパラメータを入力しない場合は、spl_autoload() 関数が登録されます。

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

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

名前空間とは何ですか?大まかに言えば、名前空間は物事をカプセル化する方法です。この抽象的な概念はさまざまな場所で見られます。たとえば、ディレクトリはオペレーティング システムで関連ファイルをグループ化するために使用され、ディレクトリ内のファイルの名前空間として機能します。たとえば、ファイル 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 年に数人のオープンソース フレームワーク開発者によって設立されました。それ以来、他の多くのメンバーが選ばれていますが、コミュニティの大部分を代表しています。 。組織の目的は、各社独自の開発スタイルがプログラム設計者の育成を妨げるトラブルを避けるために、各プロジェクトのコーディング標準を最小限の制限で統一することであるため、全員でPSRを考案・まとめ、PSRは標準勧告を提案しています(標準提案の提案)Standard Proposalの略)。

詳細な仕様と規格については、
PSR 仕様を PHP で表示できます

PSR0 標準

PRS-0 仕様は、主にいくつかの自動ロード標準 (Autoloading Standard) PSR-0 の必須要件を策定しています。 1. 完全修飾名前空間。およびクラスは次の構造に準拠する必要があります: "< ベンダー名>(< 名前空間>)*< クラス名>" 2. 各名前空間にはトップレベルの名前空間 ("ベンダー名" プロバイダー名) が必要です。

3.各名前空間は複数のサブ名前空間を持つことができます
4. ファイル システムからロードする場合、各名前空間の区切り文字 (/) は、クラス名内の各アンダースコア (_) に変換される必要があります。シンボルは DIRECTORY_SEPARATOR (オペレーティング システムのパス区切り文字) に変換されます。名前空間内では、underscore_ 記号には (特別な) 意味はありません。

6. ファイル システムからロードする場合、修飾された名前空間とクラスは .php で終わる必要があります。 7. Verdor 名、名前空間、クラス名は大文字と小文字で構成できます (大文字と小文字は区別されます)





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

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

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





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

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


まず、プログラムは PSR0 標準の第 4 条と第 5 条に準拠するマッピング関数を定義し、この関数を spl_register() に登録する必要があります。

  • 次に、新しい名前空間を定義するときは、名前空間の名前とファイルのディレクトリの場所が項目 1、2、3、および 7 に準拠している必要があります。


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

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

    次に、PSR0 標準の仕様を詳しく見てみましょう。

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

    1. 完全修飾された名前空間とクラスは、次の構造に準拠する必要があります: "< Vendor Name>(< Namespace>)*< Class Name>"

    上記 /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. ネームスペースとファイルディレクトリ間のマッピング方法が調整されました。

    2 番目の項目 (Composer の自動読み込みの原理) を詳しく説明しましょう:
    名前空間があるとします: Foo/class、Foo はユーザー定義名とディレクトリ名を含む最上位の名前空間です。マッピング関係:

    <span style="font-size: 14px;">"Foo/" => "src/"<br/></span>
    ログイン後にコピー

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

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

    <span style="font-size: 14px;">    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: 14px;">    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 サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:php.cn
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    最新の問題
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート
    私たちについて 免責事項 Sitemap
    PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!