ホームページ  >  記事  >  バックエンド開発  >  PHP オートロードと spl_autoload 自動ロード メカニズムについての深い理解_PHP チュートリアル

PHP オートロードと spl_autoload 自動ロード メカニズムについての深い理解_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-21 15:09:12755ブラウズ

PHPのオートロード機構の詳しい説明
(1) オートロード機構の概要
PHPのOOモードを利用してシステム開発を行う場合、通常は各クラスの実装を別ファイルに保存するのが一般的です。クラスの再利用が容易で、将来のメンテナンスにも便利です。これは、OO デザインの基本的な考え方の 1 つでもあります。 PHP5 より前では、クラスを使用する必要がある場合、include/require を使用してクラスを直接インクルードするだけで済みました。実際の例を次に示します。

コードをコピーします コードは次のとおりです。

/* Person.class.php */
class Person {
var $name, $age;
function __construct ($name, $age)
{
$this->name = $name;
$this->age = $age;
}
}
?>
/* no_autoload.php */
< ?php
require_once ("person.class.php");
$person = new Person("Altair", 6);
var_dump ($person);
?>

この例では、いいえ-autoload .php ファイルでは、require_once を使用して .php ファイルをインクルードする Person クラスを使用する必要があります。その後、その Person クラスを直接使用してオブジェクトをインスタンス化できます。

しかし、プロジェクトの規模が拡大し続けると、この方法を使用するといくつかの隠れた問題が発生します。PHP ファイルで他の多くのクラスを使用する必要がある場合、多くの require/include ステートメントが必要になり、省略が発生する可能性があります。不要なクラスファイルを含めます。多数のファイルで他のクラスの使用が必要な場合、各ファイルに正しいクラス ファイルが含まれていることを確認するのは悪夢のような作業になります。

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

/* autoload.php */
function __autoload($classname) {
require_once ($classname . "class.php");
}
$person = new Person("Altair", 6);
var_dump ($person);
?>

通常、PHP5 がクラスを使用するときに、クラスがロードされていないことが判明すると、自動的に __autoload() 関数が実行され、使用する必要があるクラスをロードできます。この簡単な例では、拡張子 "title="extension" >extension ".class.php" を持つクラス名を直接追加してクラス ファイル名を形成し、require_once を使用してそれをロードします。この例から、次のことができます。 autoload は少なくとも 3 つのことを行う必要があることに注意してください。1 つ目はクラス名に基づいてクラス ファイル名を決定すること、2 つ目はクラス ファイルが配置されているディスク パスを決定することです (この例では、最も単純なケースでは、クラスはそれらを呼び出す PHP プログラム ファイルと同じフォルダーにあります。3 番目のステップは、クラスをディスク ファイルからシステムにロードすることです。これは、単に include/require を使用するだけです。最初のステップ、2 番目のステップの関数は、開発中にクラス名とディスク ファイル間のマッピング方法に同意する必要があります。この方法でのみ、クラス名に基づいて対応するディスク ファイルを見つけることができます。インクルードするクラス ファイルが多数ある場合、現時点では、対応するルールを決定し、__autoload() 関数でクラス名を実際のディスク ファイルと照合するだけで、遅延読み込み効果を実現できます。ここから、__autoload() 関数の機能も確認できます。実装で最も重要なことは、クラス名と実際のディスク ファイルの間のマッピング ルールの実装です。しかし、ここで問題が発生します。システムの実装で他の多くのクラス ライブラリを使用する場合、これらのクラス ライブラリは開発者によって作成され、クラス ライブラリ ファイルの自動ロードを実装する場合は、クラス名と実際のディスク ファイルの間のマッピング ルールが異なる場合があります。この場合、__autoload() 関数は非常に複雑になるか、実装が不可能になる可能性があります。この場合、もっと単純で明確な解決策はないのでしょうか? さらなる解決策を検討する前に、次のことを考えてみましょう。 PHP での自動ロード メカニズムがどのように実装されているかを見てください。


(2) PHP の自動ロード メカニズムの実装


PHP ファイルの実行は 2 つの独立したプロセスに分割されることがわかっています。最初のステップは、PHP ファイルをコンパイルすることです。一般に OPCODE と呼ばれるバイトコード シーケンス (実際には zend_op_array と呼ばれるバイト配列にコンパイルされます)。2 番目のステップでは、これらの OPCODE を仮想マシンで実行します。したがって、実装を検討するために、PHP のすべての動作がこれらの OPCODE によって実装されます。 PHP のオートロードのメカニズムを理解するには、autoload.php ファイルを opcode にコンパイルし、これらの OPCODE を使用して PHP がプロセスで何を行ったかを調べます: /* autoload.php のコンパイルされた OPCODE リストは、によって開発された OPDUMP ツールを使用します。著者 */

コードをコピーします

コードは次のとおりです:

// require_once (”person.php”);

function __autoload ($classname) {
0 NOP
0 RECV 1
if (!class_exists($classname)) {
1 SEND_VAR !0
2 DO_FCALL 'class_exists' [extval:1]
3 BOOL_NOT $0 =>RES[~1]
4 JMPZ ~1, ->8
require_once ($classname. “.class.php”);
5 CONCAT !0, '.class.php' =>RES[~2]
6 INCLUDE_OR_EVAL ~2, REQUIRE_ONCE
}
7 JMP ->8
}
8 RETURN null

$p = 新しい人('フレッド' 、 35);
1 FETCH_CLASS '人' =>RES[:0]
2 NEW :0 =>RES[$1]
3 SEND_VAL 'フレッド'
4 SEND_VAL 35
5 DO_FCALL_BY_NAME [拡張子:2]
6 ASSIGN !0, $1

var_dump ($p);
7 SEND_VAR !0
8 DO_FCALL 'var_dump' [extval:1]
?>

autoload.php の 10 行目で、クラス Person のオブジェクトをインスタンス化する必要があります。したがって、自動ロード メカニズムは、この行のコンパイルされたオペコードに確実に反映されます。上記のコードの 10 行目で生成された OPCODE から、オブジェクト Person をインスタンス化するときに、最初に FETCH_CLASS 命令を実行する必要があることがわかります。 PHP の FETCH_CLASS 命令の処理から探索の旅を始めましょう。
PHP のソース コード (私は PHP 5.3alpha2 バージョンを使用しています) を参照すると、次の呼び出しシーケンスが見つかります:
ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, …) (zend_vm_def.h 1864 行目)
=> zend_fetch_class (zend_execute_API. c 1434 行)
=>zend_lookup_class_ex (zend_execute_API.c 964 行目)
=> zend_call_function(&fcall_info, &fcall_cache) (zend_execute_API.c 1040 行目)
呼び出しの最後のステップの前に、キーを見てみましょう呼び出しのパラメーター:
/* autoload_function 変数の値を "__autoload" に設定します */
fcall_info.function_name = &autoload_function; // おっと、ついに "__autoload" が見つかりました
...
fcall_cache.function_handler = EG(autoload_func); // autoload_func !
zend_call_function は Zend Engine で最も重要な関数の 1 つで、その主な機能は PHP プログラム内のユーザー定義関数または PHP 独自のライブラリ関数を実行することです。 zend_call_function には 2 つの重要なポインター パラメーター fcall_info と fcall_cache があり、それぞれ 2 つの重要な構造体 (1 つは zend_fcall_info 、もう 1 つは zend_fcall_info_cache) を指します。 zend_call_function の主なワークフローは次のとおりです。 fcall_cache.function_handler ポインターが NULL の場合は、fcall_info.function_name という名前の関数を検索し、存在する場合はそれを実行します。fcall_cache.function_handler が NULL でない場合は、指定された関数を直接実行します。 fcall_cache.function_handler 関数による。

これで、PHP がオブジェクトをインスタンス化するとき (実際にはインターフェイスを実装するとき、クラスでクラス定数または静的変数を使用するとき、クラスで静的メソッドを呼び出すとき)、まずシステム (またはインターフェイス) でクラスを検索することが明確にわかりました。 ) が存在する場合は、自動ロード メカニズムを使用してクラスをロードしてみてください。オートロード メカニズムの主な実行プロセスは次のとおりです。
(1) エグゼキューターのグローバル変数関数ポインター autoload_func が NULL かどうかを確認します。
(2) autoload_func==NULL の場合、__autoload() 関数がシステムに定義されているかどうかを確認し、定義されていない場合は、エラーを報告して終了します。
(3) __autoload()関数が定義されている場合は、__autoload()を実行してクラスのロードを試み、ロード結果を返します。
(4) autoload_func が NULL でない場合、autoload_func ポインタが指す関数が直接実行され、クラスがロードされます。この時点では、__autoload() 関数が定義されているかどうかはチェックされないことに注意してください。
真実がついに明らかになりました。PHP には、自動ロード メカニズムを実装するための 2 つの方法が用意されています。1 つは、前述したように、通常は PHP ソース プログラムに実装されるユーザー定義の __autoload() 関数を使用する方法です。これは、関数を設計し、その関数を指す autoload_func ポインターを指定することです。これは通常、C 言語を使用して PHP 拡張機能で実装されます。 __autoload() 関数と autoload_func の両方が実装されている場合 (autoload_func が特定の PHP 関数を指す)、autoload_func 関数のみが実行されます。

(3) SPLオートロード機構の実装
SPLとはStandard PHP Libraryの略称です。これは、PHP5 で導入された拡張ライブラリであり、その主な機能には、オートロード メカニズムとさまざまな Iterator インターフェイスまたはクラスの実装が含まれます。 SPL オートロード メカニズムは、関数ポインタ autoload_func をオートロード関数を持つ自己実装関数にポイントすることによって実装されます。 SPL には、spl_autoload と spl_autoload_call という 2 つの異なる関数があります。これら 2 つの異なる関数アドレスを autoload_func に指定することで、異なる自動ロード メカニズムが実装されます。

spl_autoload は SPL によって実装されるデフォルトの自動ロード関数であり、その機能は比較的単純です。 2 つのパラメータを受け取ることができます。最初のパラメータはクラス名を表します。2 番目のパラメータ $file_extensions は、「title="Extension">Extension」にあります。 $file_extensions" title="拡張子">拡張子名で複数の拡張子を指定します。セミコロンで区切ってください。指定しない場合は、デフォルトの拡張子"title="拡張子名"> .inc または spl_autoload が使用されます。最初に $class_name を小文字に変更し、次にすべてのインクルード パスで $class_name.inc または $class_name.php ファイルを検索します ($file_extensions パラメーターが指定されていない場合)。見つかった場合は、クラス ファイルを手動でロードします。spl_autoload を使用できます。 ("person", ".class.php") は、実際には、複数の拡張子を指定できることを除いて、require/include に似ています。

spl_autoload を自動的に動作させる方法、つまり autoload_func を spl_autoload に指定する方法は?答えは、spl_autoload_register 関数を使用することです。PHP スクリプトで初めてパラメータを指定せずに spl_autoload_register() を呼び出すと、autoload_func を spl_autoload に指定できます。

上記の説明を通じて、spl_autoload の関数は比較的単純であり、SPL 拡張機能で実装されており、その機能を拡張できないことがわかりました。独自のより柔軟な自動読み込みメカニズムを実装したい場合はどうすればよいでしょうか?この時点で、spl_autoload_call 関数がデビューします。
まず、spl_autoload_call の実装の素晴らしい機能を見てみましょう。 SPL モジュール内には、本質的に HashTable であるグローバル変数 autoload_functions がありますが、リンク リスト内の各要素は、次の機能を持つ関数を指す関数ポインターであると単純に考えることができます。クラスの自動ロード機能。 spl_autoload_call の実装自体は非常に単純で、リンクされたリスト内の各関数を順番に実行し、各関数の実行後に必要なクラスがロードされたかどうかを判断し、ロードが成功した場合はそのままリターンします。リンクされたリストの他の機能を実行し続けます。このリンクされたリスト内のすべての関数が実行された後でクラスがロードされていない場合、spl_autoload_call はユーザーにエラーを報告せずに直接終了します。したがって、オートロード メカニズムを使用しても、クラスが自動的に正しくロードされることは保証されません。キーはオートロード関数の実装方法に依存します。

では、自動ロード関数リスト autoload_functions は誰が管理するのでしょうか?先ほど述べた spl_autoload_register 関数です。ユーザー定義のオートロード関数をこのリンク リストに登録し、autoload_func 関数ポインターを spl_autoload_call 関数にポイントすることができます (例外があり、具体的な状況については全員が考えることができることに注意してください)。 spl_autoload_unregister 関数を使用して、登録された関数を autoload_functions リンク リストから削除することもできます。前のセクションで述べたように、autoload_func ポインタが null でない場合、__autoload() 関数は自動的に実行されません。autoload_func は spl_autoload_call を指しています。仕事?もちろん、引き続き spl_autoload_register(__autoload) 呼び出しを使用して、autoload_functions リンク リストに登録します。

最初のセクションの最後の質問に戻りますが、解決策はあります。各クラス ライブラリの異なる命名メカニズムに従って独自の自動ロード関数を実装し、spl_autoload_register を使用してそれらを SPL 自動ロード関数に登録します。列。 。この方法では、非常に複雑な __autoload 関数を維持する必要がありません。



(4) オートロード効率の問題と対策
オートロードメカニズムを使用するとき、多くの人が最初に抱く反応は、オートロードを使用するとシステムの効率が低下するということであり、効率性のためにオートロードを使用しないことを提案する人もいます。オートロード実装の原理を理解すると、オートロード メカニズム自体がシステム効率に影響を与える理由ではないことがわかります。これにより、不要なクラスがシステムにロードされなくなるため、システム効率が向上する可能性さえあります。
では、なぜ多くの人は自動ロードを使用するとシステム効率が低下するという印象を持っているのでしょうか?実際、オートロード メカニズムの効率に影響を与えるのは、まさにユーザー設計のオートロード機能です。クラス名を実際のディスク ファイルと効率的に一致させることができない場合 (これはファイル名だけでなく実際のディスク ファイルを指すことに注意してください)、システムは多くのファイル存在検証を実行する必要があります (各インクルード パスでの検証が必要です)。ご存知のとおり、ディスク I/O 操作の効率は非常に低いため、これが効率を低下させる原因となります。

したがって、システムを設計するときは、クラス名を実際のディスク ファイルにマッピングするための明確なメカニズムを定義する必要があります。このルールが単純かつ明確であればあるほど、自動ロード メカニズムはより効率的になります。


結論: 自動ロードメカニズムは本質的に非効率的ではありません。自動ロード機能の乱用と不適切に設計された自動ロード機能のみが効率の低下につながります。

http://www.bkjia.com/PHPjc/327352.html

tru​​ehttp://www.bkjia.com/PHPjc/327352.html技術記事 PHPのオートロード機構の詳しい説明 (1) オートロード機構の概要 ​​PHPのOOモードを利用してシステム開発を行う場合、通常は各クラスの実装を別ファイルに格納するのが一般的で、非常に...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。