依存関係の挿入については、誰もが頻繁に触れるか、少なくとも聞いたことがあると思います。Java の Spring、PHP の Laravel、Symfony など、比較的よく知られたフレームワークはすべて依存関係の挿入をサポートしています。 、など。次に、単純な DI コンテナを手動で実装してみましょう。
運転から始めましょう
最初に車を運転して例を挙げましょう:
class Driver{ public function drive() { $car = new Car(); echo '老司机正在驾驶', $car->getCar(), PHP_EOL; } }class Car{ protected $name = '普通汽车'; public function getCar() { return $this->name; } }
経験者向けには、ドライバーと車の 2 つのカテゴリがありますdrivers Driver にはメソッド driver があり、呼び出すときは、まず車全体 $car を取得してから車を起動します。ほとんどの学生がこのコードまたは同様のコードを作成したことがありますが、このコードには何も問題はなく、ごく普通のコードです。でも、車を乗り換えるなら普通の車では女の子を惹きつけることはできません。
class Benz extends Car{ protected $name = '奔驰'; }
現時点では、かなり嫌な操作を行う必要があり、古いドライバーのコードを変更する必要があります。 (老ドライバー「何を間違えたんだろう?車を乗り換えたら、運転免許証を勉強し直さなければいけない…)」したがって、経験豊富なドライバーが運転時に独自の車を構築する必要がなくなるように、車を外部の世界に注入し、ドライバーと車を切り離す必要があります。したがって、次の結果が得られます。
class Driver{ protected $car; public function __construct(Car $car) { $this->car = $car; } public function drive() { echo '老司机正在驾驶', $this->car->getCar(), PHP_EOL; } }
現時点では、Driver クラスと Car クラスは分離されており、これら 2 つのクラスの依存関係は上位層のコードによって管理されています。このとき、経験豊富なドライバーは次のように「運転」します。
$car = new Car(); $driver = new Driver($car); $driver->drive();
この時点で、ドライバーの依存関係のインスタンスを作成し、それを注入します。上記の例では依存性注入を実装しましたが、手動であるため、やはり書くのに違和感がありました。このような大変な作業をどうやって手動で行うことができるでしょうか? プログラムにそれを自動的に行わせる必要があります。それ以来、DI コンテナーが誕生しました。
Dependency Injection Container
Dependency Injection は、IoC モデルやファクトリ モデルと同様に、呼び出し元と呼び出し先の間の依存関係の結合関係を解決するモデルです。オブジェクト間の依存関係を解決し、オブジェクトが IoC/DI コンテナのみに依存し、相互に直接依存しなくなることで疎結合が実現され、オブジェクトの作成時に IoC/DI コンテナがその依存関係 (依存関係) を注入します。 ) オブジェクト (注入)、これにより最大限の疎結合を実現できます。率直に言うと、依存関係の注入とは、コンテナが、特定のクラスが依存する他のクラスのインスタンスを、このクラスのインスタンスに注入することを意味します。
この段落は少し抽象的かもしれませんが、先ほどの例に戻りましょう。私は依存関係の注入を手動で完了しましたが、これは非常に面倒ですが、これを大規模なプロジェクトで実行すると、間違いなく非常に煩雑で十分な洗練度が得られません。したがって、これを行うスチュワードが必要であり、このスチュワードがコンテナです。クラスの依存関係管理はすべてコンテナーに任せられます。したがって、一般的に言えば、コンテナは全員が共有するグローバル オブジェクトです。
独自の DI コンテナを作成する
関数を作成するには、まず問題を分析する必要があります。そのため、まず、単純な DI コンテナにどのような関数が必要かを理解する必要があります。これは、次のことに直接関係します。私たちの準備規定。単純なコンテナの場合、少なくとも次の点を満たす必要があります:
必要なクラスのインスタンスを作成する
完全な依存関係管理 (DI) )
- #シングルトンのインスタンスを取得できます ##世界的に一意の
- ##要約すると、コンテナ クラスは次のようになります:
class Container{ /** * 单例 * @var Container */ protected static $instance; /** * 容器所管理的实例 * @var array */ protected $instances = []; private function __construct(){} private function __clone(){} /** * 获取单例的实例 * @param string $class * @param array ...$params * @return object */ public function singleton($class, ...$params) {} /** * 获取实例(每次都会创建一个新的) * @param string $class * @param array ...$params * @return object */ public function get($class, ...$params) {} /** * 工厂方法,创建实例,并完成依赖注入 * @param string $class * @param array $params * @return object */ protected function make($class, $params = []) {} /** * @return Container */ public static function getInstance() { if (null === static::$instance) { static::$instance = new static(); } return static::$instance; } }一般的なスケルトンが決定され、コアの make メソッドに入ります:
protected function make($class, $params = []){ //如果不是反射类根据类名创建 $class = is_string($class) ? new ReflectionClass($class) : $class; //如果传的入参不为空,则根据入参创建实例 if (!empty($params)) { return $class->newInstanceArgs($params); } //获取构造方法 $constructor = $class->getConstructor(); //获取构造方法参数 $parameterClasses = $constructor ? $constructor->getParameters() : []; if (empty($parameterClasses)) { //如果构造方法没有入参,直接创建 return $class->newInstance(); } else { //如果构造方法有入参,迭代并递归创建依赖类实例 foreach ($parameterClasses as $parameterClass) { $paramClass = $parameterClass->getClass(); $params[] = $this->make($paramClass); } //最后根据创建的参数创建实例,完成依赖的注入 return $class->newInstanceArgs($params); } }コンテナを使いやすくするために、次のようにしました。 シングルトン インスタンスを配列から直接取得できるように、ArrayAccess インターフェイスを実装します。インスタンスが存在しない場合は、インスタンスを作成します。
- __get メソッドをオーバーライドします。これはより便利です。
- の最終バージョンを取得します。
class Container implements ArrayAccess{ /** * 单例 * @var Container */ protected static $instance; /** * 容器所管理的实例 * @var array */ protected $instances = []; private function __construct(){} private function __clone(){} /** * 获取单例的实例 * @param string $class * @param array ...$params * @return object */ public function singleton($class, ...$params) { if (isset($this->instances[$class])) { return $this->instances[$class]; } else { $this->instances[$class] = $this->make($class, $params); } return $this->instances[$class]; } /** * 获取实例(每次都会创建一个新的) * @param string $class * @param array ...$params * @return object */ public function get($class, ...$params) { return $this->make($class, $params); } /** * 工厂方法,创建实例,并完成依赖注入 * @param string $class * @param array $params * @return object */ protected function make($class, $params = []) { //如果不是反射类根据类名创建 $class = is_string($class) ? new ReflectionClass($class) : $class; //如果传的入参不为空,则根据入参创建实例 if (!empty($params)) { return $class->newInstanceArgs($params); } //获取构造方法 $constructor = $class->getConstructor(); //获取构造方法参数 $parameterClasses = $constructor ? $constructor->getParameters() : []; if (empty($parameterClasses)) { //如果构造方法没有入参,直接创建 return $class->newInstance(); } else { //如果构造方法有入参,迭代并递归创建依赖类实例 foreach ($parameterClasses as $parameterClass) { $paramClass = $parameterClass->getClass(); $params[] = $this->make($paramClass); } //最后根据创建的参数创建实例,完成依赖的注入 return $class->newInstanceArgs($params); } } /** * @return Container */ public static function getInstance() { if (null === static::$instance) { static::$instance = new static(); } return static::$instance; } public function __get($class) { if (!isset($this->instances[$class])) { $this->instances[$class] = $this->make($class); } return $this->instances[$class]; } public function offsetExists($offset) { return isset($this->instances[$offset]); } public function offsetGet($offset) { if (!isset($this->instances[$offset])) { $this->instances[$offset] = $this->make($offset); } return $this->instances[$offset]; } public function offsetSet($offset, $value) { } public function offsetUnset($offset) { unset($this->instances[$offset]); } }次に、コンテナーを使用して、上記を記述してみましょうコード:
$driver = $app->get(Driver::class); $driver->drive();//output:老司机正在驾驶普通汽车复制代码シンプルで経験豊富な運転手が電車を発車させることができます。ここでのデフォルトの注入は Car のインスタンスです。メルセデス ベンツを運転する必要がある場合は、これを実行するだけです:
$benz = $app->get(Benz::class); $driver = $app->get(Driver::class, $benz); $driver->drive();//output:老司机正在驾驶奔驰复制代码PSR-11 の要件に従って、依存関係注入コンテナーは次の実装を行う必要があります。 Psr\Container\ContainerInterface インターフェイス。これは単なるデモンストレーションです。これを実装するには、Psr 依存関係ライブラリの導入が必要なので、より面倒ですが、実際には非常に簡単です。メソッドがいくつかあるだけです。興味のある方は、PSR-11 (ポータル) の要件について自分で学ぶことができます。 これは非常に単純な DI コンテナです。実際には、考慮すべきことがたくさんありますが、ここでのコンテナ関数は依然として非常に単純です。循環依存関係への対処方法や遅延読み込みの仕組みなど、まだ対処できていない落とし穴がいくつかあります... ここでは私の週末の練習記録を少しだけ載せておきます。 Laravel または Symfony コンテナーのソース コードについては以下を読むか、Spring のコンテナーについて学ぶことができます。時間があるときに引き続き改良していきます。 [推奨学習:「
PHP ビデオ チュートリアル
」]以上がPHP DI コンテナを手動で作成する方法を説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHPは死にかけていませんが、常に適応して進化しています。 1)PHPは、1994年以来、新しいテクノロジーの傾向に適応するために複数のバージョンの反復を受けています。 2)現在、電子商取引、コンテンツ管理システム、その他の分野で広く使用されています。 3)PHP8は、パフォーマンスと近代化を改善するために、JITコンパイラおよびその他の機能を導入します。 4)Opcacheを使用してPSR-12標準に従って、パフォーマンスとコードの品質を最適化します。

PHPの将来は、新しいテクノロジーの傾向に適応し、革新的な機能を導入することで達成されます。1)クラウドコンピューティング、コンテナ化、マイクロサービスアーキテクチャに適応し、DockerとKubernetesをサポートします。 2)パフォーマンスとデータ処理の効率を改善するために、JITコンパイラと列挙タイプを導入します。 3)パフォーマンスを継続的に最適化し、ベストプラクティスを促進します。

PHPでは、特性は方法が必要な状況に適していますが、継承には適していません。 1)特性により、クラスの多重化方法が複数の継承の複雑さを回避できます。 2)特性を使用する場合、メソッドの競合に注意を払う必要があります。メソッドの競合は、代替およびキーワードとして解決できます。 3)パフォーマンスを最適化し、コードメンテナビリティを改善するために、特性の過剰使用を避け、その単一の責任を維持する必要があります。

依存関係噴射コンテナ(DIC)は、PHPプロジェクトで使用するオブジェクト依存関係を管理および提供するツールです。 DICの主な利点には、次のものが含まれます。1。デカップリング、コンポーネントの独立したもの、およびコードの保守とテストが簡単です。 2。柔軟性、依存関係を交換または変更しやすい。 3.テスト可能性、単体テストのために模擬オブジェクトを注入するのに便利です。

SplfixedArrayは、PHPの固定サイズの配列であり、高性能と低いメモリの使用が必要なシナリオに適しています。 1)動的調整によって引き起こされるオーバーヘッドを回避するために、作成時にサイズを指定する必要があります。 2)C言語アレイに基づいて、メモリと高速アクセス速度を直接動作させます。 3)大規模なデータ処理とメモリに敏感な環境に適していますが、サイズが固定されているため、注意して使用する必要があります。

PHPは、$ \ _ファイル変数を介してファイルのアップロードを処理します。セキュリティを確保するための方法には次のものが含まれます。1。アップロードエラー、2。ファイルの種類とサイズを確認する、3。ファイル上書きを防ぐ、4。ファイルを永続的なストレージの場所に移動します。

JavaScriptでは、nullcoalescingoperator(??)およびnullcoalescingsignmentoperator(?? =)を使用できます。 1.??最初の非潜水金または非未定されたオペランドを返します。 2.??これらの演算子は、コードロジックを簡素化し、読みやすさとパフォーマンスを向上させます。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

MantisBT
Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境

SublimeText3 中国語版
中国語版、とても使いやすい

PhpStorm Mac バージョン
最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。
