ThinkPHP5.1ソースコードの浅い分析(二)自動ロードメカニズム
9837 ワード
ライフサイクル第2編に引き続き、ハトの文章を勝手に書かないで安心してください.
第1編では、エントランススクリプトについてもお話ししましたが、自動ロード機能も登録されていますこの文書のデフォルトでは、自動ロードとネーミングスペースの基礎があります.この記事を参照してくださいphpクラスの自動ロードとネーミングスペース オートローディングメカニズム
phpの自動ロードは
私たちのプログラムはここでLoaderの静的メソッドを実行し、同時にこれもすべてのクラス
register()メソッド実行プロセス
登録システムの自動ロード
このメソッドは行数が長すぎます.少しずつ分析します.
これは私たちの自動ロード関数を登録して、
この関数を知らない人は、文章の一番上の接続を見てください.詳しく説明してあります.
Composerオートローディングサポート
composer拡張をサポートするため、自動登録時にcomposerもついでに登録して、拡張の呼び出しを便利にしました.
autoload_static.phpの変数をメモリにロードするには、autoload_のための難題があります.static.phpファイルのクラス名は常に変化しており、固定されたクラス名は得られません.(私のシステムのクラス名が
まず、プログラムにロードされたすべてのクラス名を取得し、最後にロードされたクラス名(配列の最後)を取得します.
クラス名を取得し、
質問:composer_staticのパラメータは何を表しますか?
ClassMap(ネーミングスペースマッピング)
直接ネーミング空間のフルネームとディレクトリのマッピングは,単純で乱暴であり,この配列もかなり大きい.
PSR 4標準トップクラスのネーミングスペースマッピング配列:
PSR 4標準の最上位ネーミングスペースマッピングには2つの配列が使用され、1つ目はネーミングスペースの最初のアルファベットを接頭辞インデックスとして使用し、次に最上位ネーミングスペースとして使用されますが、最終的にはファイルパスではなく、最上位ネーミングスペースの長さです.どうしてですか.
PSR 4規格は、トップネームスペースディレクトリをトップネームスペースディレクトリに置き換えるため、トップネームスペースの長さを得ることが重要である.
これらの配列の役割を具体的に説明します.
このレコードは、キーが最上位のネーミングスペースであり、値がネーミングスペースの長さです.上位ネーミングスペースを取得した後、
次に、ネーミングスペース
注:実は1つのwebフレームワークとして、composerの中のものは、ThinkPHPが関心を持つべきではありませんが、TP 5自身のオリジナルのフレームワークパッケージのデザインがcomposerを完全に含んでいないため、登録が自動的にロードされるときにその属性値を持って自分で使用します(自分の理解に限られ、あなたの観点と異なる場合は議論を歓迎します)
ネームスペース定義の登録
この後のコードは大きく異なり、必要なクラスを
TP 5コードで
クラスライブラリマッピングファイルが生成され、
自動ロードの使用
この状態ではErrorは存在せず,我々の自動ロードメソッドに入って再試行する.
断片を切り取って少しずつ分析します.
このセクションでは、クラスに別名を設定するかどうかを判断しますが、明らかに設定されていません.
見つかったらlinuxとwindowのパス名の違いを解消します.(linuxは大文字と小文字を厳密に区別しますが、winは厳密に区別しません)
ここでは主にwindow環境でパス名の大文字と小文字が区別されないことを心配しているので、linuxのディレクトリルールに基づいてファイルパスを書き直しました.
後でディレクトリファイルを追加します
第1編では、エントランススクリプトについてもお話ししましたが、自動ロード機能も登録されています
phpの自動ロードは
Loader
クラスで実現され,このクラスはbase.php
に導入された.//base .php
// Loader
require __DIR__ . '/library/think/Loader.php';
//
Loader::register();
私たちのプログラムはここでLoaderの静的メソッドを実行し、同時にこれもすべてのクラス
register()
です.私たちはLoader.php
に入り、上の実行順序でそのコアが何であるかを見てみましょう.register()メソッド実行プロセス
登録システムの自動ロード
このメソッドは行数が長すぎます.少しずつ分析します.
//
spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);
これは私たちの自動ロード関数を登録して、
$autoload
この変数は伝達のパラメータで、あなたが自分で自分のロードクラスを実現することができることを考慮して、便利に開拓するために、TPはあなたに自分のクラスのロード方法を実現させることができます.この関数を知らない人は、文章の一番上の接続を見てください.詳しく説明してあります.
Composerオートローディングサポート
$rootPath = self::getRootPath();
self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR;
// Composer
if (is_dir(self::$composerPath)) {
if (is_file(self::$composerPath . 'autoload_static.php')) {
require self::$composerPath . 'autoload_static.php';
//
$declaredClass = get_declared_classes();
$composerClass = array_pop($declaredClass);
foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) {
if (property_exists($composerClass, $attr)) {
self::${$attr} = $composerClass::${$attr};
}
}
} else {
self::registerComposerLoader(self::$composerPath);
}
}
composer拡張をサポートするため、自動登録時にcomposerもついでに登録して、拡張の呼び出しを便利にしました.
autoload_static.phpの変数をメモリにロードするには、autoload_のための難題があります.static.phpファイルのクラス名は常に変化しており、固定されたクラス名は得られません.(私のシステムのクラス名が
ComposerStaticInit5109814b18095308ffe89ba7a1be18df
のように)require self::$composerPath . 'autoload_static.php';
の属性をプログラムにロードするために、ここでは形式を変えました.まず、プログラムにロードされたすべてのクラス名を取得し、最後にロードされたクラス名(配列の最後)を取得します.
$declaredClass = get_declared_classes();
$composerClass = array_pop($declaredClass);
クラス名を取得し、
property_exists($composerClass, $attr)
を呼び出してクラスに指定された属性があるかどうかを確認します.質問:composer_staticのパラメータは何を表しますか?
foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) ('fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files') ?
ClassMap(ネーミングスペースマッピング)
public static $classMap = array (
'App\\Http\\Controllers\\Auth\\ForgotPasswordController'
=> __DIR__ . '/../..' . '/app/Http/Controllers/Auth/ForgotPasswordController.php',
'App\\Http\\Controllers\\Auth\\LoginController'
=> __DIR__ . '/../..' . '/app/Http/Controllers/Auth/LoginController.php',
'App\\Http\\Controllers\\Auth\\RegisterController'
=> __DIR__ . '/../..' ,
……
)
直接ネーミング空間のフルネームとディレクトリのマッピングは,単純で乱暴であり,この配列もかなり大きい.
PSR 4標準トップクラスのネーミングスペースマッピング配列:
public static $prefixLengthsPsr4 = array(
'p' => array (
'phpDocumentor\\Reflection\\' => 25,
),
'S' => array (
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Component\\Yaml\\' => 23,
'Symfony\\Component\\VarDumper\\' => 28,
...
),
...);
public static $prefixDirsPsr4 = array (
'phpDocumentor\\Reflection\\' => array (
0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src',
1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src',
2 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src',
),
'Symfony\\Polyfill\\Mbstring\\' => array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Component\\Yaml\\' => array (
0 => __DIR__ . '/..' . '/symfony/yaml',
),
...)
PSR 4標準の最上位ネーミングスペースマッピングには2つの配列が使用され、1つ目はネーミングスペースの最初のアルファベットを接頭辞インデックスとして使用し、次に最上位ネーミングスペースとして使用されますが、最終的にはファイルパスではなく、最上位ネーミングスペースの長さです.どうしてですか.
PSR 4規格は、トップネームスペースディレクトリをトップネームスペースディレクトリに置き換えるため、トップネームスペースの長さを得ることが重要である.
これらの配列の役割を具体的に説明します.
Symfony\Polyfill\Mbstring\example
というネーミングスペースを探すと、接頭辞インデックスと文字列マッチングで得られます.'Symfony\\Polyfill\\Mbstring\\' => 26,
このレコードは、キーが最上位のネーミングスペースであり、値がネーミングスペースの長さです.上位ネーミングスペースを取得した後、
$prefixDirsPsr4
配列に行ってマッピングディレクトリ配列を取得します.(マッピングディレクトリは1つではない可能性があります) array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
)
次に、ネーミングスペース
Symfony\\Polyfill\\Mbstring\\example
の最初の26文字をディレクトリ__DIR__ . '/..' . '/symfony/polyfill-mbstring
に置き換えることができ、ディスク上のこのファイルが存在しないかどうかを確認してから、__DIR__ . '/..' . '/symfony/polyfill-mbstring/example.php
を得ることができます.ループ後に見つからない場合は、ロードに失敗します.注:実は1つのwebフレームワークとして、composerの中のものは、ThinkPHPが関心を持つべきではありませんが、TP 5自身のオリジナルのフレームワークパッケージのデザインがcomposerを完全に含んでいないため、登録が自動的にロードされるときにその属性値を持って自分で使用します(自分の理解に限られ、あなたの観点と異なる場合は議論を歓迎します)
ネームスペース定義の登録
//
self::addNamespace([
'think' => __DIR__,
'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',
]);
//
if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {
self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));
}
// extend
self::addAutoLoadDir($rootPath . 'extend');
この後のコードは大きく異なり、必要なクラスを
Psr4
という静的変数にマッピングしています.ネーミングスペースを使用して呼び出すのに便利です.//
if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {
self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));
}
TP 5コードで
php think optimize:autoload
を実行するとruntimeでclassmapが生成する.phpファイル、ファイル形式return [
'app\\index\\controller\\Index' => 'D:/app/tp5/application/' . 'index/controller/Index.php',
'think\\App' => 'D:/app/tp5/thinkphp/library/' . '/think/App.php',
'think\\Build' => 'D:/app/tp5/thinkphp/library/' . '/think/Build.php',
'think\\Cache' => 'D:/app/tp5/thinkphp/library/' . '/think/Cache.php',
'think\\Collection' => 'D:/app/tp5/thinkphp/library/' . '/think/Collection.php',
...
]
クラスライブラリマッピングファイルが生成され、
runtime
ディレクトリの下にclassmap.php
ファイルが生成され、生成されたクラスライブラリマッピングファイルはシステムディレクトリとアプリケーションディレクトリのクラスライブラリをスキャンします.その後出会ったらそのまま持ってきて、システムの自動ロードの性能を高めます.register()
関数ここでは大体解析が終わります.ここでは登録自動ロードについて説明します.自動ロードの使用
register
において,関数式Loader::autoload()
を自動的にロードする方法を定義した.私たちのbase.php
では、自動ロードメカニズムをロードすると、異常処理がロードされます.// Loader
require __DIR__ . '/library/think/Loader.php';
//
Loader::register();
//
Error::register();
この状態ではErrorは存在せず,我々の自動ロードメソッドに入って再試行する.
//
public static function autoload($class)
{
if (isset(self::$classAlias[$class])) {
return class_alias(self::$classAlias[$class], $class);
}
if ($file = self::findFile($class)) {
// Win
if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
return false;
}
__include_file($file);
return true;
}
}
断片を切り取って少しずつ分析します.
if (isset(self::$classAlias[$class])) {
return class_alias(self::$classAlias[$class], $class);
}
このセクションでは、クラスに別名を設定するかどうかを判断しますが、明らかに設定されていません.
if ($file = self::findFile($class)) {
// Win
if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
return false;
}
__include_file($file);
return true;
}
findFile($class)
classMapをruntimeフォルダの下にキャッシュした場合、彼は直接戻ります.(これはclassMapをキャッシュするとパフォーマンスが向上する理由です)、キャッシュがなければマッピング関係を格納していた静的配列prefixDirsPsr4
とprefixLengthsPsr4
を組み合わせてファイルのディレクトリを探すと、速度が比較的遅くなります.見つからなければ空に戻り、 spl_autoload_register
はクラスが見つからないと判断し、エラーを投げ出す.見つかったらlinuxとwindowのパス名の違いを解消します.(linuxは大文字と小文字を厳密に区別しますが、winは厳密に区別しません)
ここでは主にwindow環境でパス名の大文字と小文字が区別されないことを心配しているので、linuxのディレクトリルールに基づいてファイルパスを書き直しました.
後でディレクトリファイルを追加します