PHP を学ぶときに多くの友人が直面する最初の問題の 1 つは、require、include と require_once、include_once の間の愛と死です。
彼らの愛と死の物語を理解した後、彼らはしばしばフレームを使い始めます。フレームワークは確かに仕事に適したツールですが、通常、新しいクラスを作成すると何が起こるかご存知ですか?仕様に従っていると、なぜすべてが自動的にロードされるのか疑問に思ったことはありますか? 探索して謎を発見しましょう。
タイムライン
Steam Age
PHP コードの先頭にこのようなコードがよく見られますか。
require 'lionis.php'; require 'is.php'; require 'cool.php';
PHP スクリプトをいくつか紹介するだけであれば、問題ありません。何千ものスクリプトが導入されると、爆発は避けられません。スクリプトの名前を変更すると、変更されたスクリプトを導入する各スクリプトの名前も変更する必要があります。爆発することはありませんか?この文を入力することさえ回避するにはどうすればよいでしょうか?
電気の時代
PHP の電気の時代には、カスタムの自動読み込み戦略を登録するための __autoload 関数と spl_autoload_register 関数が登場し始めました。
平たく言えば、__autoloadとspl_autoload_registerはキラー組織であり、各国からキラー(機能)を雇うことになります。誰か (新規) を削除したい場合、名前 (クラス名) を指定するだけで済み、残りの「Killer」がそれを完了するのに役立ちます。
__autoload
PHP 5 ではこの機能ポータルの提供を開始しました。使用するクラスが見つからない場合は、クラス名をパラメータとしてこの関数にスローします。
<?php// Lionis.phpclass Lionis { public function __construct() { echo '欧耶耶, 我就是 Lionis'; } }
<?php // index.php function __autoload($classname) { $filename = './' . $classname . '.php'; require_once $filename; } $lionis = new Lionis();
Output
欧耶耶, 我就是 Lionis
spl_autoload_register
私たちのプロジェクトが非常に大規模で古い場合、またはあなたが投げるのが大好きな若いパイオニアである場合、現時点では、導入する必要があるものの仕様が異なります。 __autoload関数、この関数は近々拡張される予定です。さらに、__autoload はグローバルに一意であるため、他のものによって占有されているとエラーが発生する可能性があります。 (人を滅ぼすには、まずそれを膨らませる必要があります。)
PHP 5.1.2 は、この関数ポータルの提供を開始し、指定された関数を __autoload の実装として登録します。したがって、一部のフレームワークまたはプラグインを使用する場合、互換性のために function_exists(spl_autoload_register) が表示される場合があります。
<?php function lionisIsCoolFind($classname) { require './' . $classname . '.php'; } // 函数 spl_autoload_register('lionisIsCoolFind'); // 匿名函数 spl_autoload_register(function($require) { require './' . $classname . '.php'; }); // 类中的函数 spl_autoload_register(array('Lionis', 'loadClass'));
そうそう、これでさまざまな自動読み込み関数を作成できるようになりました。
情報化時代
マスター、気をつけてください、この先には悪魔がいます! 。各人が独自のオートローディング メソッドのセットを実装する場合、各 PHP コンポーネントとフレームワークは独自のオートローダーを使用し、各フレームワークは異なるロジックを使用して PHP クラス、インターフェイス、およびトレイトをロードします。
その後、サードパーティのフレームワークを使用する場合は、ブート ファイル内のオートローダーを理解する必要もあります。これには非常に時間がかかります。 PHP-FIG はこの問題を認識しており、オートローダーを使用できるようにコンポーネント間の相互運用性を促進するために PSR-4 仕様を使用することを推奨しています。
PSR-4 规范
利用命名空间的前缀和文件系统中的目录对应起来。
映射关系为
namespace => filePath \Lionis\Cool => cool
带有命名空间的类
<?php // 该文件为 cool/Real.phpnamespace \ Lionis\Cool;class Real { }
创建一个对象
<?php// 该文件为 index.php$lionis = new \ Lionis\Cool\Real;
这个时候,按照 PSR-4 的规范,自动加载器应该去加载 cool/ 目录下的 Real.php。
不对!那这样不是还要自己去实现 自动加载器 嘛,不然怎么 无中生有 出现 自动加载器 呢?难道官方 内置 了?
你 out 了吧,我们可以使用依赖管理器 composer 来生成 PSR-4 自动加载器。你可能会疑问,那我的旧项目没有遵循 PSR-4 规范怎么办?嘿嘿,让我们来探索发现一下 composer 是怎么解决这个问题的吧。
Composer
哦吼吼,我们这次的重点在与探究自动加载,所以 composer 的安装和使用等,就不去讨论了。
composer 自动加载设置了 4种 加载方式:
PSR-0
PSR-4
classmap
files
PSR-0
要求命名空间和目录层层对应,且可以使用 _ 作为路径分隔符,但是这会导致目录结果变得过深。
在 composer 执行 install 等操作时,composer 会把文件中的配置存储在 vendor/composer/autoload_psr0.php文件中的返回数组中。
例如:定义了Very\Good=>vendor\Lionis\IsReal\Cool,在调用 use Very\Good\Love\SomeClass,PSR-0 加载的实际目录为 vendor/Lionis/IsReal/Cool/Very/Good/Love/SomeClass.php。
对吧,这简直深得吓人,所以 PSR-0 被官方废除了。但是一些主流的框架已经实现了 PSR-0,为了向下兼容还是要实现 PSR-0。
composer.json配置:
"autoload": { "psr-0": { "Very\\Good": "vendor\Lionis\IsReal\Cool" } }
PSR-4
PSR-4 是现在比较推荐的方法,用于替代 PSR-0。
与 PSR-0 不同的是,取消掉了 _ 作为分隔符和目录结构。
在 composer 执行 install 等操作时,composer 会把文件中的配置存储在 vendor/composer/autoload_psr4.php文件中的返回数组中。
例如:定义了Very\Good=>vendor\Lionis\IsReal\Cool,在调用 use Very\Good\
Love\SomeClass,PSR-4 加载的实际目录为 vendor/Lionis/IsReal/Cool/Love/SomeClass.php。
composer.json配置:
"autoload": { "psr-4": { "Very\\Good": "vendor\Lionis\IsReal\Cool" } }
classmap
classmap 通过配置指定的目录和文件,在 composer 执行 install 等操作时,composer 会去扫描对应的目录下以.php结尾的文件中的 class,并存储在 vendor/composer/autoload_classmap.php文件中的返回数组中。
composer.json配置:
"autoload": { "classmap": [ "Lionis/", "Xiaoer/" ] }
如果 Lionis 下有一个叫 VeryCool的文件,那么在vendor/composer/autoload_classmap.php 中会生成。
<?php // autoload_classmap.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'VeryCool' => $baseDir . '/Lionis/VeryCool.php', // 其他的映射 );
files
files 就是直接简单粗暴的加载文件。在 composer 执行 install 等操作时,composer 会把文件中的配置存储在vendor/composer/autoload_static.php文件中的生成一个 $files 数组。
composer.json 配置:
"autoload": { "files": ["Lionis/Very/Cool.php"] }