私はlaravelに触れ始めたばかりで、1日でいくつかの公式ドキュメントを読んだ後、laravelを学び始めました。ここで説明することは最も基本的なことなので、専門家はすべて読み飛ばして構いません。
作曲家の概要
最初、私が最も惹かれたのは Composer でした。これまで Composer を使用したことがなかったからです。
Composer は、依存関係を管理するために PHP で使用されるツールです。プロジェクト内で依存する外部ツール ライブラリを宣言するだけで、Composer がこれらの依存ライブラリ ファイルのインストールを支援します。 Composer を実行するには、PHP 5.3.2+ 以降が必要です。
コンポーザーを使用する
最初のステップは、依存関係を宣言することです。ロギング用のライブラリが必要なプロジェクトを作成しているとします。あなたは monolog を使用することにしました。これをプロジェクトに追加するには、プロジェクトの依存関係を説明する composer.json
ファイルを作成するだけです。
2 番目のステップは、コンポーザーを使用することです。プロジェクトのルートディレクトリでインストールコマンドを実行します。実行後、monolog が vendor/monolog/monolog
ディレクトリにダウンロードされます。
3 番目のステップは、クラスの自動ロードです。ライブラリのダウンロードに加えて、Composer は Composer によってダウンロードされたライブラリ内のすべてのクラス ファイルをロードできる自動ロード ファイルも用意しています。これを使用するには、次のコード行をプロジェクトのブートストラップ ファイルに追加するだけです:
リーリーこれにより、サードパーティのコードを簡単に使用できるようになります。たとえば、プロジェクトが monolog に依存している場合、次のようにライブラリの使用を開始すると、それらは自動的にロードされます。
リーリー
Composer の自動読み込み探索
現実世界でツールを使用するとき、そのツールがどのように機能するかを理解していれば、より自信を持ってツールを使用できるようになります。初めて Laravel と Composer を使用する初心者の場合、Composer の仕組みを理解していれば、より快適に使用できるようになります。
私の理解では、composer は宣言された依存関係に基づいて関連するライブラリのソースからコード ファイルをダウンロードし、依存関係に基づいて Composer ディレクトリにクラスを自動ロードするための PHP スクリプトを生成します。これを使用する場合は、先頭に「/」を導入します。プロジェクト Vendor/autoload.php" ファイルを使用すると、これらのサードパーティ ライブラリのクラスを直接インスタンス化できます。では、Composer はクラスの自動ロードをどのように実装するのでしょうか?次にlaravelのエントリーファイルから順を追ってComposerの自動読み込みの謎を見ていきましょう。
1.コードリストlaravel/public/index.php
リーリー最初の行では、説明なしで laravel/bootstrap/autoload.php が紹介されているので、ファイルを開いてください。
2. コードリストlaravel/bootstrap/autoload.php
リーリー最初の行は、プログラムが実行を開始する時点を定義します。 2行目の直後にlaravel/vendor/autoload.phpが導入されています。
7 行目は、前述したように、Composer の autoload.php を導入した後、サードパーティのクラス ライブラリのクラスを直接使用できるようになります。これは、直接使用される Bootup クラスです。 /vendor/autoload.php が実際に何をするのかを見てみましょう。
3. コードリスト laravel/vendor/autoload.php
リーリーここに着いたら、すぐに自動追加されたドアに入ります。
このファイルは非常に単純ですが、5 行目の関数名に混乱していますか?心配しないでください。これは単なるクラス名です。このクラスは、3 行目で紹介されているファイル laravel/vendor/composer/autoload_real.php で宣言されています。 次に、ファイルを開いて getLoader();
を確認してください。
4. コードリストlaravel/vendor/composer/autoload_real.php
リーリー17 行目の getLoader() は、まず現在のクラスの $loader 値を決定し、それが null でない場合はそれを返します。これはスキップできます。次に、ClassLoader クラスを $loader、laravel/vendor/composer/ClassLoader.php
にインスタンス化します。ここではいくつかのファイルが紹介されています。これらのファイルは、composer によって自動的に生成されます。依存関係が変更された場合、これらのスクリプトを変更する必要はなく、composer を実行するだけで再生成されます。
laravel/vendor/composer/autoload_namespace.php
laravel/vendor/composer/autoload_prs4.php
laravel/vendor/composer/autoload_classmap.php
laravel/vendor/composer/autoload_files.php
一連のパス情報を設定した後、$loader->set()、$loader->setPsr4()、$loader->addClassMap()を実行し、その後、$loader->register(true); を実行しました。それでは、一つずつ見ていきましょう。
5. コードリストlaravel/vendor/composer/ClassLoader.php
1 8f8ec00954a843cf8c4c6c750bc33ea3 7 * ジョルディ・ボジャーノ e3ca9ebaa50b2a0eb224087c18163e31 8 * 9 * 完全な著作権およびライセンス情報については、ライセンスを参照してください。 10 * このソースコードとともに配布されたファイル。 11 */ 12 13 名前空間 ComposerAutoload; 14 15/** 16 * ClassLoader は PSR-0 クラスローダーを実装します 17 * 18 * https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md を参照してください。 19 * 20 * $loader = new ComposerAutoloadClassLoader(); 21 * 22 * // クラスを名前空間に登録する 23 * $loader->add('SymfonyComponent', __DIR__.'/component'); 24 * $loader->add('Symfony', __DIR__.'/framework'); 25 * 26 * // オートローダーをアクティブにする 27 * $loader->register(); 28 * 29 * // インクルード パスの検索を有効にします (例: PEAR パッケージの場合) 30 * $loader->setUseIncludePath(true); 31 * 32 * この例では、SymfonyComponent 内のクラスを使用しようとすると 33 * 名前空間またはその子の 1 つ (たとえば SymfonyComponentConsole)、 34 * オートローダーはまず、component/ の下のクラスを検索します。 35 * ディレクトリ。そうでない場合は、framework/ ディレクトリにフォールバックします。 36 * 諦める前に見つけました。 37 * 38 * このクラスは、Symfony UniversalClassLoader に大まかに基づいています。 39 * 40 * @author Fabien Potencier 2a8de6f724f98fd078e5ee98b2dc3ecf 41 * @author Jordi Boggiano e3ca9ebaa50b2a0eb224087c18163e31 42 */ 43 クラス クラスローダー 44 { 45 // PSR-4 46 プライベート $prefixLengthsPsr4 = array(); 47 プライベート $prefixDirsPsr4 = array(); 48 プライベート $fallbackDirsPsr4 = array(); 49 50//PSR-0 51 プライベート $prefixesPsr0 = array(); 52 プライベート $fallbackDirsPsr0 = array(); 53 54 private $useIncludePath = false; 55 プライベート $classMap = array(); 56 57 パブリック 関数 getPrefixes() 58 { 59 return call_user_func_array('array_merge', $this->prefixesPsr0); 60 } 61 62 パブリック 関数 getPrefixesPsr4() 63 { 64 return $this->prefixDirsPsr4; 65 } 66 67 パブリック 関数 getFallbackDirs() 68 { 69 return $this->fallbackDirsPsr0; 70 } 71 72 パブリック 関数 getFallbackDirsPsr4() 73 { 74 return $this->fallbackDirsPsr4; 75 } 76 77 パブリック 関数 getClassMap() 78 { 79 戻る $this->クラスマップ; 80 } 81 82/** 83 * @param array $classMap クラスからファイル名へのマップ 84 */ 85 public function addClassMap(array $classMap) 86 { 87 if ($this->クラスマップ) { 88 $this->classMap = array_merge($this->classMap, $classMap); 89 } else { 90 $this->classMap = $classMap; 91 } 92 } 93 94/** 95 * 指定されたプレフィックスの PSR-0 ディレクトリのセットを登録します。 96 * このプレフィックスに対して以前に設定されたものに追加または追加します。 97 * 98 * @param string $prefix プレフィックス 99 * @param array|string $paths PSR-0 ルート ディレクトリ 100 * @param bool $prepend ディレクトリを先頭に追加するかどうか 101 */ 102 public function add($prefix, $paths, $prepend = false) 103 { 104 if (!$prefix) { 105 if ($prepend) { 106 $this->fallbackDirsPsr0 = array_merge( 107 (配列) $パス、 108 $this->fallbackDirsPsr0 109 ); 110 } else { 111 $this->fallbackDirsPsr0 = array_merge( 112 $this->fallbackDirsPsr0, 113 (配列) $パス 114 ); 115 } 116 117 戻る; 118 } 119 120 $first = $prefix[0]; 121 if (!isset($this->prefixesPsr0[$first][$prefix])) { 122 $this->prefixesPsr0[$first][$prefix] = (array) $paths; 123 124 戻る; 125 } 126 if ($prepend) { 127 $this->prefixesPsr0[$first][$prefix] = array_merge( 128 (配列) $パス、 129 $this->prefixesPsr0[$first][$prefix] 130 ); 131 } else { 132 $this->prefixesPsr0[$first][$prefix] = array_merge( 133 $this->prefixesPsr0[$first][$prefix]、 134 (配列) $パス 135 ); 136 } 137 }138 139 /** 140 * 指定された名前空間の PSR-4 ディレクトリのセットを登録します。 141 * この名前空間に以前に設定されたものに追加または先頭に追加します。 142 * 143 * @param string $prefix 接頭辞/名前空間 (末尾に「\」が付きます) 144 * @param array|string $paths PSR-0 のベース ディレクトリ 145 * @param bool $prepend ディレクトリを先頭に追加するかどうか 146 */ 147 public function addPsr4($prefix, $paths, $prepend = false) 148 { 149 if (!$prefix) { 150 // ルート名前空間のディレクトリを登録します。 151 if ($prepend) { 152 $this->fallbackDirsPsr4 = array_merge( 153 (配列) $パス、 154 $this->fallbackDirsPsr4 155 ); 156 } else { 157 $this->fallbackDirsPsr4 = array_merge( 158 $this->fallbackDirsPsr4, 159 (配列) $パス 160 ); 161 } 162 } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 163 // 新しい名前空間のディレクトリを登録します。 164 $length = strlen($prefix); 165 if ('\' !== $prefix[$length - 1]) { 166 throw new InvalidArgumentException("空でない PSR-4 プレフィックスは名前空間区切り文字で終わる必要があります。"); 167 } 168 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 169 $this->prefixDirsPsr4[$prefix] = (配列) $paths; 170 } elseif ($prepend) { 171 // すでに登録されている名前空間のディレクトリを先頭に追加します。 172 $this->prefixDirsPsr4[$prefix] = array_merge( 173 (配列) $パス、 174 $this->prefixDirsPsr4[$prefix] 175 ); 176 } else { 177 // すでに登録されている名前空間のディレクトリを追加します。 178 $this->prefixDirsPsr4[$prefix] = array_merge( 179 $this->prefixDirsPsr4[$prefix]、 180 (配列) $パス 181 ); 182 } 183 } 184 185 /** 186 * 指定されたプレフィックスの PSR-0 ディレクトリのセットを登録します。 187 * このプレフィックスに対して以前に設定された他のものを置き換えます。 188 * 189 * @param string $prefix プレフィックス 190 * @param array|string $paths PSR-0 のベース ディレクトリ 191 */ 192 public function set($prefix, $paths) 193 { 194 if (!$prefix) { 195 $this->fallbackDirsPsr0 = (配列) $paths; 196 }他 { 197 $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 198 } 199 } 200 201 /** 202 * 指定された名前空間の PSR-4 ディレクトリのセットを登録します。 203 * この名前空間に対して以前に設定された他のものを置き換えます。 204 * 205 * @param string $prefix 接頭辞/名前空間 (末尾に「\」が付きます) 206 * @param array|string $paths PSR-4 のベース ディレクトリ 207 */ 208 public function setPsr4($prefix, $paths) { 209 if (!$prefix) { 210 $this->fallbackDirsPsr4 = (配列) $paths; 211 } else { 212 $length = strlen($prefix); 213 if ('\' !== $prefix[$length - 1]) { 214 throw new InvalidArgumentException("空でない PSR-4 プレフィックスは名前空間区切り文字で終わる必要があります。"); 215 } 216 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 217 $this->prefixDirsPsr4[$prefix] = (配列) $paths; 218 } 219 } 220 221 /** 222 * クラス ファイルのインクルード パスの検索をオンにします。 223 * 224 * @param bool $useIncludePath 225 */ 226 public function setUseIncludePath($useIncludePath) 227 { 228 $this->useIncludePath = $useIncludePath; 229 } 230 231 /** 232 * オートローダーがインクルードパスを使用してチェックするかどうかを確認するために使用できます 233 *クラス用。 234 * 235 * @return bool 236 */ 237 パブリック 関数 getUseIncludePath() 238 { 239 return $this->useIncludePath; 240 } 241 242 /** 243 * このインスタンスをオートローダーとして登録します。 244 * 245 * @param bool $prepend オートローダーを先頭に追加するかどうか 246 */ 247 public function register($prepend = false) 248 { 249 spl_autoload_register(array($this, 'loadClass'), true, $prepend); 250 } 251 252 /** 253 * このインスタンスをオートローダーとして登録解除します。 254 */ 255 public function unregister() 256 { 257 spl_autoload_unregister(array($this, 'loadClass')); 258 }259 260 /** 261 * 指定されたクラスまたはインターフェイスをロードします。 262 * 263 * @param string $class クラスの名前 264 * @return bool|null ロードされている場合は true、それ以外の場合は null 265 */ 266 public functionloadClass($class) 267 { 268 if ($file = $this->findFile($class)) { 269 includeFile($file); 270 271 戻る 本当; 272 } 273 } 274 275 /** 276 * クラスが定義されているファイルへのパスを検索します。 277 * 278 * @param string $class クラスの名前 279 * 280 * @return string|false 見つかった場合はパス、それ以外の場合は false 281 */ 282 public function findFile($class) 283 { 284 // PHP 5.3.0 - 5.3.2 の回避策 https://bugs.php.net/50731 285 if ('\' == $class[0]) { 286 $class = substr($class, 1); 287 } 288 289 //クラスマップルックアップ 290 if (isset($this->classMap[$class])) { 291 return $this->classMap[$class]; 292 } 293 294 $file = $this->findFileWithExtension($class, '.php'); 295 296 // HHVM で実行している場合は、Hack ファイルを検索します 297 if ($file === null && 定義('HHVM_VERSION')) { 298 $file = $this->findFileWithExtension($class, '.hh'); 299 } 300 301 if ($file === null) { 302 // このクラスは存在しないことに注意してください。 303 return $this->classMap[$class] = false; 304 } 305 306 戻る $ファイル; 307 } 308 309 プライベート 関数 findFileWithExtension($class, $ext) 310 { 311 // PSR-4 ルックアップ 312 $logicalPathPsr4 = strtr($class, '\', DIRECTORY_SEPARATOR) 。 $ext; 313 314 $first = $class[0]; 315 if (isset($this->prefixLengthsPsr4[$first])) { 316 foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { 317 if (0 === strpos($class, $prefix)) { 318 foreach ($this->prefixDirsPsr4[$prefix] as $dir) { 319 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { 320 返却 $ファイル; 321 } 322 }323 } 324 } 325 } 326 327 // PSR-4 フォールバック ディレクトリ 328 foreach ($this->fallbackDirsPsr4 as $dir) { 329 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 330 返却 $ファイル; 331 } 332 } 333 334 // PSR-0 ルックアップ 335 if (false !== $pos = strrpos($class, '\')) { 336 // 名前空間クラス名 337 $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 338 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 339 } else { 340 // PEAR風のクラス名 341 $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) 。 $ext; 342 } 343 344 if (isset($this->prefixesPsr0[$first])) { 345 foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 346 if (0 === strpos($class, $prefix)) { 347 foreach ($dir as $dir) { 348 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 349 戻る $ファイル; 350 } 351 } 352 } 353 } 354 } 355 356 // PSR-0 フォールバック ディレクトリ 357 foreach ($this->fallbackDirsPsr0 as $dir) { 358 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 359 戻る $ファイル; 360 } 361 } 362 363 // PSR-0 にはパスが含まれます。 364 if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 365 戻る $ファイル; 366 } 367 } 368} 369 370 /** 371 * 分離された範囲には以下が含まれます。 372 * 373 * インクルードされたファイルから $this/self へのアクセスを防止します。 374 */ 375 関数 includeFile($file) 376 { 377 インクルード $ファイル; 378 } コードを表示$loader->set($namespace, $path);Psr0标準
その後の関連ファイルの自動アップロードを容易にするために、名前空間に対応するパスを設定します。
$loader->setPsr4($namespace, $path);Psr4標準
その後の関連するファイルの自動アップロードを容易にするために、名前空間に対応するパスを設定します。
$loader->addClassMap($classMap);
その後の関連ファイルの自動アップロードを容易にするために、クラス名に対応するファイル パスを設定します。
$loader->登録(true);
<span>public</span> <span>function</span> register(<span>$prepend</span> = <span>false</span><span>) { spl_autoload_register(</span><span>array</span>(<span>$this</span>, 'loadClass'), <span>true</span>, <span>$prepend</span><span>); }</span>
这里设置了 欲注册的自动装载函数 $this->loadClass(),关于 spl_autoload_register 和 spl_autoload_unregister 的更多信息随后会有专门的解释。现在打开loadClass()的定义
<span>public</span> <span>function</span> loadClass(<span>$class</span><span>) { </span><span>if</span> (<span>$file</span> = <span>$this</span>->findFile(<span>$class</span><span>)) { includeFile(</span><span>$file</span><span>); </span><span>return</span> <span>true</span><span>; } }</span>
这里有个 findFile() 函数,如果相关类的声明所在文件的路径找到了,就包含并运行该文件,然后返回 true 。接着打开findFile()的定义
<span>public</span> <span>function</span> findFile(<span>$class</span><span>) { </span><span>//</span><span> work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731</span> <span>if</span> ('\\' == <span>$class</span>[0<span>]) { </span><span>$class</span> = <span>substr</span>(<span>$class</span>, 1<span>); } </span><span>//</span><span> class map lookup</span> <span>if</span> (<span>isset</span>(<span>$this</span>->classMap[<span>$class</span><span>])) { </span><span>return</span> <span>$this</span>->classMap[<span>$class</span><span>]; } </span><span>$file</span> = <span>$this</span>->findFileWithExtension(<span>$class</span>, '.php'<span>); </span><span>//</span><span> Search for Hack files if we are running on HHVM</span> <span>if</span> (<span>$file</span> === <span>null</span> && <span>defined</span>('HHVM_VERSION'<span>)) { </span><span>$file</span> = <span>$this</span>->findFileWithExtension(<span>$class</span>, '.hh'<span>); } </span><span>if</span> (<span>$file</span> === <span>null</span><span>) { </span><span>//</span><span> Remember that this class does not exist.</span> <span>return</span> <span>$this</span>->classMap[<span>$class</span>] = <span>false</span><span>; } </span><span>return</span> <span>$file</span><span>; }</span>
先是判断类名是否以'\'开始,如果是的话,清除开头的'\'
接着,检查当前类的名字是否在 类名与声明当前类的文件的路径的关系数组 中,如果存在,直接返回相关键值(类文件路径信息)
如果上一步没有返回路径信息,执行 findFileWithExtension($class, '.php') 继续查找类文件路径信息,findFileWithExtension的定义后面将会列出。
如果仍未找到类的文件路径信息,返回值为 null 且定义了 HHVM_VERSION 信息,则用“.hh”后缀继续查找类文件信息。
HHVM_VERSION 是 HHVM版本信息? HHVM 是 Facebook 开发的高性能 PHP 虚拟机,宣称比官方的快9倍。
如果仍未找到,则返回 false 。Remember that this class does not exist.(这句注释很有喜感?哈哈)
代码清单 findFileWithExtension()
<span> 1</span> <span>private</span> <span>function</span> findFileWithExtension(<span>$class</span>, <span>$ext</span><span>) </span><span> 2</span> <span>{ </span><span> 3</span> <span>//</span><span> PSR-4 lookup</span> <span> 4</span> <span>$logicalPathPsr4</span> = <span>strtr</span>(<span>$class</span>, '\\', DIRECTORY_SEPARATOR) . <span>$ext</span><span>; </span><span> 5</span> <span> 6</span> <span>$first</span> = <span>$class</span>[0<span>]; </span><span> 7</span> <span>if</span> (<span>isset</span>(<span>$this</span>->prefixLengthsPsr4[<span>$first</span><span>])) { </span><span> 8</span> <span>foreach</span> (<span>$this</span>->prefixLengthsPsr4[<span>$first</span>] <span>as</span> <span>$prefix</span> => <span>$length</span><span>) { </span><span> 9</span> <span>if</span> (0 === <span>strpos</span>(<span>$class</span>, <span>$prefix</span><span>)) { </span><span>10</span> <span>foreach</span> (<span>$this</span>->prefixDirsPsr4[<span>$prefix</span>] <span>as</span> <span>$dir</span><span>) { </span><span>11</span> <span>if</span> (<span>file_exists</span>(<span>$file</span> = <span>$dir</span> . DIRECTORY_SEPARATOR . <span>substr</span>(<span>$logicalPathPsr4</span>, <span>$length</span><span>))) { </span><span>12</span> <span>return</span> <span>$file</span><span>; </span><span>13</span> <span> } </span><span>14</span> <span> } </span><span>15</span> <span> } </span><span>16</span> <span> } </span><span>17</span> <span> } </span><span>18</span> <span>19</span> <span>//</span><span> PSR-4 fallback dirs</span> <span>20</span> <span>foreach</span> (<span>$this</span>->fallbackDirsPsr4 <span>as</span> <span>$dir</span><span>) { </span><span>21</span> <span>if</span> (<span>file_exists</span>(<span>$file</span> = <span>$dir</span> . DIRECTORY_SEPARATOR . <span>$logicalPathPsr4</span><span>)) { </span><span>22</span> <span>return</span> <span>$file</span><span>; </span><span>23</span> <span> } </span><span>24</span> <span> } </span><span>25</span> <span>26</span> <span>//</span><span> PSR-0 lookup</span> <span>27</span> <span>if</span> (<span>false</span> !== <span>$pos</span> = <span>strrpos</span>(<span>$class</span>, '\\'<span>)) { </span><span>28</span> <span>//</span><span> namespaced class name</span> <span>29</span> <span>$logicalPathPsr0</span> = <span>substr</span>(<span>$logicalPathPsr4</span>, 0, <span>$pos</span> + 1<span>) </span><span>30</span> . <span>strtr</span>(<span>substr</span>(<span>$logicalPathPsr4</span>, <span>$pos</span> + 1), '_',<span> DIRECTORY_SEPARATOR); </span><span>31</span> } <span>else</span><span> { </span><span>32</span> <span>//</span><span> PEAR-like class name</span> <span>33</span> <span>$logicalPathPsr0</span> = <span>strtr</span>(<span>$class</span>, '_', DIRECTORY_SEPARATOR) . <span>$ext</span><span>; </span><span>34</span> <span> } </span><span>35</span> <span>36</span> <span>if</span> (<span>isset</span>(<span>$this</span>->prefixesPsr0[<span>$first</span><span>])) { </span><span>37</span> <span>foreach</span> (<span>$this</span>->prefixesPsr0[<span>$first</span>] <span>as</span> <span>$prefix</span> => <span>$dirs</span><span>) { </span><span>38</span> <span>if</span> (0 === <span>strpos</span>(<span>$class</span>, <span>$prefix</span><span>)) { </span><span>39</span> <span>foreach</span> (<span>$dirs</span> <span>as</span> <span>$dir</span><span>) { </span><span>40</span> <span>if</span> (<span>file_exists</span>(<span>$file</span> = <span>$dir</span> . DIRECTORY_SEPARATOR . <span>$logicalPathPsr0</span><span>)) { </span><span>41</span> <span>return</span> <span>$file</span><span>; </span><span>42</span> <span> } </span><span>43</span> <span> } </span><span>44</span> <span> } </span><span>45</span> <span> } </span><span>46</span> <span> } </span><span>47</span> <span>48</span> <span>//</span><span> PSR-0 fallback dirs</span> <span>49</span> <span>foreach</span> (<span>$this</span>->fallbackDirsPsr0 <span>as</span> <span>$dir</span><span>) { </span><span>50</span> <span>if</span> (<span>file_exists</span>(<span>$file</span> = <span>$dir</span> . DIRECTORY_SEPARATOR . <span>$logicalPathPsr0</span><span>)) { </span><span>51</span> <span>return</span> <span>$file</span><span>; </span><span>52</span> <span> } </span><span>53</span> <span> } </span><span>54</span> <span>55</span> <span>//</span><span> PSR-0 include paths.</span> <span>56</span> <span>if</span> (<span>$this</span>->useIncludePath && <span>$file</span> = stream_resolve_include_path(<span>$logicalPathPsr0</span><span>)) { </span><span>57</span> <span>return</span> <span>$file</span><span>; </span><span>58</span> <span> } </span><span>59</span> }
该函数唯一的目的就是根据刚才通过$loader->set($namespace, $path)和$loader->setPsr4($namespace, $path)方法设置的信息找出类文件的路径信息。
接下来,我们回到代码清单laravel/vendor/composer/autoload_real.php ,为精简篇幅,这里只贴出片段(续上节的 $loader->register(true))。
<span>$loader</span>->register(<span>true</span><span>); </span><span>$includeFiles</span> = <span>require</span> __DIR__ . '/autoload_files.php'<span>; </span><span>foreach</span> (<span>$includeFiles</span> <span>as</span> <span>$file</span><span>) { composerRequire9b2a1b1cf01c9a870ab98748dc5f1256(</span><span>$file</span><span>); } </span><span>return</span> <span>$loader</span><span>; } } </span><span>function</span> composerRequire9b2a1b1cf01c9a870ab98748dc5f1256(<span>$file</span><span>) { </span><span>require</span> <span>$file</span><span>; }</span>
在经历了一番长途跋涉后,终于从 laravel/vendor/composer/ClassLoader.php 中出来了。继 $loader->register(true) 之后,又引入了laravel/vendor/composer/autoload_files.php,相比之下,这个文件要简单得多,只是个数组,列出了几个文件路径。
<span>//</span><span> autoload_files.php @generated by Composer</span> <span>$vendorDir</span> = <span>dirname</span>(<span>dirname</span>(<span>__FILE__</span><span>)); </span><span>$baseDir</span> = <span>dirname</span>(<span>$vendorDir</span><span>); </span><span>return</span> <span>array</span><span>( </span><span>$vendorDir</span> . '/ircmaxell/password-compat/lib/password.php', <span>$vendorDir</span> . '/swiftmailer/swiftmailer/lib/swift_required.php', <span>$vendorDir</span> . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php', <span>$vendorDir</span> . '/laravel/framework/src/Illuminate/Support/helpers.php',<span> );</span>
接着就是用 composerRequire9b2a1b1cf01c9a870ab98748dc5f1256() 函数 包含并运行 这几个文件。这四个文件的具体信息,随后会专门写博文来认识。
最后 , 返回 ClassLoader 类的实例 $loader 。
现在在回到 代码清单 laravel/bootstrap/autoload.php 的第7行
<span>1</span> <span>define</span>('LARAVEL_START', <span>microtime</span>(<span>true</span><span>)); </span><span>2</span> <span>require</span> __DIR__.'/../vendor/autoload.php'<span>; </span><span>3</span> <span>if</span> (<span>file_exists</span>(<span>$compiled</span> = __DIR__.'/compiled.php'<span>)) </span><span>4</span> <span>{ </span><span>5</span> <span>require</span> <span>$compiled</span><span>; </span><span>6</span> <span>} </span><span>7</span> Patchwork\Utf8\Bootup::initMbstring();
注意这里第7行,之所以可以直接像 Patchwork\Utf8\Bootup::initMbstring() 这么使用而不需要手动required Bootup类文件,是因为 前面在ClassLoader中的register() 函数用 spl_autoload_register() 对Bootup类进行了注册。下面说一下 spl_autoload_register 。
spl_autoload_register
要使用 spl_autoload_register ,请保证你的PHP版本(PHP 5 >= 5.1.2)。
www.php.net 对 spl_autoload_register 的解释如下:注册__autoload()函数,将函数注册到SPL __autoload函数栈中。如果该栈中的函数尚未激活,则激活它们。刚接触 PHP 的同学肯定觉得这个解释云里雾里的,看完依然不知道什么意思。要想理解这句话,首先要弄明白 __autoload() 是个什么东西。
__autoload()
__autoload 的作用是尝试加载未定义的类,可以通过定义这个函数来启用类的自动加载。下面举个例子:
<span>function</span> __autoload(<span>$class</span><span>) { </span><span>echo</span> '尝试加载的类的名字是:'.<span>$class</span><span>; } </span><span>$say</span>= @ <span>new</span> say();
上例会输出:"尝试加载的类的名字是 say "。由于最后一行引用了尚未定义的类 box ,所以 __autoload 函数将被执行。
再看下面这段
class say { public function __construct() { echo 'say 类存在,并说出了hello,所以 __autoload 函数不会执行。'; } } <span>function</span> __autoload(<span>$class</span><span>) { </span><span>echo</span> '尝试加载的类的名字是:'.<span>$class</span><span>; } </span><span>$say</span>= @ <span>new</span> say();
这将会输出 : say 类存在,并说出了hello,所以 __autoload 函数不会执行。
理解完 __autoload 就好办了,再看上面:“将函数注册到SPL __autoload函数栈中”,意思是我们可以自定义 尝试加载未定义的类时 使用的函数。现在返回代码片段
spl_autoload_register(<span>array</span>(<span>$this</span>, 'loadClass'), <span>true</span>, <span>$prepend</span>);
这下是不是很明白了,当实例化一个类的时候,如果这个类没有定义,就执行 ClassLoader 类中的 loadClass 函数。loadClass 的定义前面我们说过了,就是找到声明相关类的文件,然后包含并运行该文件,随后加载相关类。至此,composer的自动加载机制学习完毕。
。