ホームページ >バックエンド開発 >PHPチュートリアル >PHPマスター|にきびによる依存噴射

PHPマスター|にきびによる依存噴射

Christopher Nolan
Christopher Nolanオリジナル
2025-02-24 08:57:10511ブラウズ

PHP Master | Dependency Injection with Pimple

コアポイント

  • 依存関係注射はアプリケーション開発の重要な概念であり、依存関係をハードコードではなくモジュールに注入することにより、より効率的で保守可能なコードを記述できます。
  • Pimpleは、PHPの閉鎖を使用して依存関係を管理しやすい方法で定義する単純な依存噴射コンテナです。
  • 依存関係を注入するための2つの主な手法は、コンストラクターベースの依存関係注入とセッターベースの注入であり、それぞれに独自の利点と短所があります。
  • Pimpleは、依存関係を定義し、重複を回避し、アプリケーションでサービスを管理および集中させるのを容易にするコンテナとして機能することにより、ソフトウェア開発の乾燥した原理をサポートします。
  • Pimpleは、共有オブジェクトを使用して同じインスタンスを返す機能や、元の実装に影響を与えることなく既存の閉鎖を動的に変更する機能などの高度な機能も提供します。

アプリケーション開発では、将来のプロジェクトでコードを再利用するスタンドアロンモジュールを作成しようとします。ただし、有用な機能を提供する完全に独立したモジュールを作成することは困難です。これは、コードがモジュールにハードコードせずに適切に機能するために必要な依存関係を注入できるため、依存関係の注入が役立つ場所です。 Pimpleは、PHPの閉鎖を利​​用して管理可能な方法で依存関係を定義する単純な依存噴射コンテナです。この記事では、ハードコーディングされた依存関係の問題、依存関係の噴射がこれらの問題をどのように解決するか、およびPimpleを使用して依存関係の噴射を容易にするコードを使用する方法を調査します。

特定の依存関係の問題

アプリケーションを作成するときは、多くのPHPクラスを使用します。クラスは、予想される機能を提供するために他の1つ以上のクラスのメソッドを呼び出す必要がある場合があるため、最初のクラスは他のクラスに依存すると言います。たとえば、

<code class="language-php"><?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}</code>

クラスAはクラスBに依存しますクラスBが利用できない場合、上記のコードは機能しません。さらに、クラス内のオブジェクトの作成をハードコードするたびに、クラスに特定の依存関係があります。特定の依存関係は、テスト可能なコードを作成する障壁です。より良いアプローチは、クラスBのオブジェクトをクラスAに提供することです。これらのオブジェクトは、Aのコンストラクターまたはセッターメソッドで提供できます。さらに議論する前に、より現実的なシナリオを見てみましょう。

ソーシャルネットワークサイトでのコンテンツの共有は最近では非常に一般的であり、ほとんどのWebサイトはソーシャルプロファイルフィードがウェブサイトに直接表示されます。 Twitter、Facebook、Googleなどのソーシャルサイトからフィードを生成するSocialFeedsというクラスがあるとします。これらの各サービスを処理するための個別のクラスを作成します。ここでは、Twitterと対話するクラスTwitterServiceを見ていきます。 SocialFeedsクラスはTwitterServiceを使用してTwitterフィードを要求します。 TwitterServiceはデータベースと対話して、APIにアクセスする特定のユーザートークンを取得します。トークンはOAuthクラスに渡され、提供されたトークンを使用してフィードを取得し、SocialFeedsクラスに返します。

<code class="language-php"><?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}</code>
<code class="language-php"><?php
class SocialFeeds
{
    public function getSocialFeeds() {
        $twService = new TwitterService();
        echo $twService->getTweets();
    }
}</code>
<code class="language-php"><?php
class TwitterService
{
    public function getTweets() {
        $db = new DB();
        $query = "Query to get user token from database";
        $token = $db->getQueryResults($query);

        $oauth = new OAuth();
        return $oauth->requestTwitterFeed($token);
    }
}</code>
<code class="language-php"><?php
class OAuth
{
    public function requestTwitterFeed($token) {
        // Retrieve and return twitter feed using the token         
    }
}</code>

SocialFeedsがTwitterserviceに依存していることは明らかです。しかし、TwitterServiceはDBとOAUTHに依存するため、ソーシャルフィードは間接的にDBとOAUTHに依存します。では、何が問題なのでしょうか? SocialFeedsは3つのクラスの具体的な実装に依存しているため、他のクラスの実際の実装なしにソーシャルフィードを個別にテストすることは不可能です。または、別のデータベースまたは別のOAUTHプロバイダーを使用すると仮定します。この場合、コード全体の既存のクラスを新しいクラスに置き換える必要があります。

特定の依存関係を修正

これらの依存関係の解決策は単純です。つまり、具体的な実装を使用せずに必要に応じてオブジェクトを動的に提供します。依存関係を注入できる手法には、コンストラクターベースの依存関係注入とセッターベースのインジェクションの2種類があります。

コンストラクターベースの注入

コンストラクターベースの依存関係注入を使用して、依存関係オブジェクトは外部から作成され、クラスのコンストラクターにパラメーターとして渡されます。これらのオブジェクトをクラス変数に割り当て、クラス内のどこでも使用できます。 SocialFeedsクラスのコンストラクターベースの注入は次のとおりです。

<code class="language-php"><?php
class DB
{
    public function getQueryResults($query) {
        // Get results from database and return token
    }
}</code>
TwitterServiceのインスタンスは、コンストラクターのオブジェクトとして渡されます。 SocialFeedsは依然としてTwitterServiceに依存していますが、今ではTwitterサービスプロバイダーのさまざまなバージョン、さらにはテスト目的のためにオブジェクトを模倣することさえできます。 TwitterServiceに関しては、DBおよびOAUTHクラスも同様の方法で定義されます。

<code class="language-php"><?php
class SocialFeeds
{
    public $twService;

    public function __construct($twService) {
        $this->twService = $twService;
    }

    public function getSocialFeeds() {
        echo $this->twService->getTweets();
    }
}</code>

販売者ベースの注入

セッターベースのインジェクションを使用して、オブジェクトはコンストラクターの代わりにセッターメソッドによって提供されます。以下は、SocialFeedsクラスのセッターベースの依存関係インジェクションの実装です。

初期化コードにはDBが含まれ、OAuthは次のようになりました。
<code class="language-php"><?php
$db = new DB();
$oauth = new OAuth();
$twService = new TwitterService($db, $oauth);
$socialFeeds = new SocialFeeds($twService);
$socialFeeds->getSocialFeeds();</code>

コンストラクターとセッター噴射
<code class="language-php"><?php
class SocialFeeds
{
    public $twService;

    public function getSocialFeeds() {
        echo $this->twService->getTweets();
    }

    public function setTwitterService($twService) {
        $this->twService = $twService;
    }
}</code>

選択装置ベースのインジェクションまたはセッターベースの注入はあなた次第です。コンストラクターベースの注入は、クラスをインスタンス化するためにすべての依存関係が必要な場合に適しています。セッターベースの注入は、毎回依存関係が必要ない場合に適しています。

プロ

コンストラクター - クラスのコンストラクターを見て、クラスのすべての依存関係を識別してください

    Setor -新しい依存関係を追加することは、新しいセッターメソッドを追加するのと同じくらい簡単で、既存のコードを壊さない
  • 短所

  • コンストラクター - 新しい依存関係を追加すると、コンストラクター全体に既存のコードを追加する必要があります。
  • setor-どこにも指定されていないため、必要な依存関係を手動で検索する必要があります
依存関係の注入とさまざまな注入技術を理解した後、今度はにきびとそれがどのように適合するかを見る時が来ました。

di におけるピンプルの役割

前述のテクニックを使用して依存関係を既に挿入できる場合、なぜニキビが必要なのか疑問に思うかもしれません。この質問に答えるには、乾燥した原理を見る必要があります。

自分自身を繰り返さないでください(DRY)は、さまざまな情報の重複を減らすことを目的としたソフトウェア開発の原則です。これは、多層アーキテクチャで特に役立ちます。乾燥した原則の声明は、「すべての知識の断片には、システムに単一の明確な権威ある表現が必要だ」ということです。

コンストラクターベースの注入例を検討してください。 SocialFeedクラスのオブジェクトが必要になるたびに、依存関係をインスタンス化して渡すというセットアッププロセス全体を繰り返す必要があります。 Dryによると、メンテナンスの問題を防ぐために、そのようなコードを避ける必要があります。 Pimpleは、重複を避けるためにそのような依存関係を定義する容器として機能します。シンプルな例を見て、にきびがどのように機能するかを見てみましょう。

依存関係を保存するための容器としてpimpleのインスタンスを作成します。 SPL ArrayAccessインターフェイスを実装するため、それを使用することは配列の使用に非常に似ています。まず、必要なクラスの名前を保持するキーを定義します。次に、閉鎖を定義して、サービスとして機能する指定されたクラスのインスタンスを返します。コンテナのインスタンスは$ Cに渡されるため、必要に応じて他の定義されたキーを参照できます。これで、クラスのインスタンスが必要なときはいつでも、キーを参照してオブジェクトを取得できます。 SocialFeedsの例をPimpleに変換しましょう。公式のPimple Webサイトの例は、コンストラクターベースの注入を示しているため、セッターベースの注入を説明します。 Pimpleを使用するには、以前に定義されたセッターメソッドやコードを変更する必要はないことを忘れないでください。ロジックをカプセル化するだけです。
<code class="language-php"><?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}</code>

DBとOAUTHクラスはどちらも独立したモジュールであるため、閉鎖内で新しいインスタンスを直接返します。次に、セッターベースのインジェクションを使用して、Twitterserviceクラスに依存関係を追加します。 DBとOAUTHクラスをコンテナに追加したため、$ C ['db']および$ c ['oauth']を使用して、関数内に直接アクセスできます。これで、依存関係はサービスとしてコンテナ内にカプセル化されます。別のDBクラスまたは別のOAuthサービスを使用したいときはいつでも、コンテナステートメントのクラスを交換するだけで、すべてが完全に実行されます。 Pimpleを使用すると、1つの場所に新しい依存関係を追加するだけです。
<code class="language-php"><?php
class SocialFeeds
{
    public function getSocialFeeds() {
        $twService = new TwitterService();
        echo $twService->getTweets();
    }
}</code>

高度なpimple使用

上記のシナリオでは、Pimpleは要求されるたびに各クラスの新しいインスタンスを閉鎖から返します。場合によっては、データベースに接続するなど、毎回新しいインスタンスを初期化せずに同じオブジェクトを使用する必要があります。 Pimpleは、共有オブジェクトを使用して同じインスタンスを返す機能を提供します。

また、これまでのところ、にきび容器内の単一の場所ですべての依存関係を定義しています。ただし、依存関係を持つが元のサービスとはわずかに異なる構成を行うサービスが必要な場合を検討してください。たとえば、ORMにアクセスしてTwitterServiceクラスの機能を実装する必要があるとします。既存の閉鎖は、すべての既存の関数をORMの使用に強制するため、変更することはできません。 Pimpleは、元の実装に影響を与えることなく、既存の閉鎖を動的に変更するためのextend()メソッドを提供します。次のコードを検討してください:

<code class="language-php"><?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}</code>

ここで、特別な場合にTweet_Serviceのさまざまな拡張バージョンを使用できます。最初のパラメーターはサービスの名前で、2番目のパラメーターはオブジェクトインスタンスとコンテナにアクセスできる関数です。実際、extend()は、さまざまな状況に合わせて依存関係を動的に追加する強力な方法ですが、重複コードの量を増やすため、拡張バージョンのサービスを最小限に制限してください。

<code class="language-php"><?php
class SocialFeeds
{
    public function getSocialFeeds() {
        $twService = new TwitterService();
        echo $twService->getTweets();
    }
}</code>

概要

依存関係の管理は、Webアプリケーション開発における最も重要で困難なタスクの1つです。コンストラクターとセッターメソッドの依存関係注入を使用して、それらを効果的に管理できます。ただし、依存関係の注入自体にもいくつかの問題があり、Pimpleはこれらの問題を解決し、軽量の容器を提供してオブジェクトの依存関係を乾燥方法で作成および保存することで解決します。以下のコメントで、プロジェクトの依存関係の管理と依存関係の挿入容器としてのPimpleについての考えを自由に共有してください。

における依存性注入についてのFAQ(FAQ)

にきびとは何ですか?なぜPHPで使用されているのですか?

Pimpleは、アプリケーションのサービスを管理および集中化できる単純なPHP依存噴射コンテナです。 PHPで使用されているため、コードの柔軟性が高まり、再利用可能で、テストが容易になります。 Pimpleを使用することにより、オブジェクトを1つの場所にインスタンス化し、アプリケーションのさまざまな部分に注入して、グローバル状態の必要性を減らし、コードを維持とテストしやすくすることができます。

にきびはどのように機能しますか?

Pimpleは、コンテナにサービス定義を保存することで機能します。これらの定義は呼び出され(関数または方法)、​​サービスのインスタンスを返します。コンテナからサービスにアクセスすると、Pimpleはサービス定義を実行してサービスオブジェクトを作成します。これにより、アプリケーション全体で集中的にサービスを管理し、サービスを共有できます。

pimpleをインストールする方法は?

Pimpleは、Composer(PHPの依存関係管理ツール)を使用してインストールできます。 Composerをシステムにグローバルにインストールしてから、コマンドを実行してプロジェクトにPimpleを導入できます。

pimpleでサービスを定義する方法は?

Pimpleでは、コンテナ内のキーに呼び出し可能なオブジェクトを割り当てることにより、サービスを定義できます。呼び出し可能なオブジェクトは、サービスのインスタンスを返す必要があります。たとえば、このようなメール送信者クラスのサービスを定義できます。

$container['mailer'] = function ($c) { return new Mailer($c['smtp']); }; この例では、メール送信者サービスは、SMTPサービスが依存関係として挿入されるメーラークラスの新しいインスタンスとして定義されます。

pimpleでサービスにアクセスする方法は?

サービスキーを使用して配列表記を使用して、Pimpleのサービスにアクセスできます。たとえば、次のようなメール送信者サービスにアクセスできます:

。サービスにアクセスすると、Pimpleはサービス定義を実行し、サービスオブジェクトを返します。

$mailer = $container['mailer'];にきびでサービスを共有する方法は?

デフォルトでは、Pimpleはサービスにアクセスするたびにサービスの新しいインスタンスを返します。サービスを共有し、毎回同じインスタンスを返したい場合は、

メソッドを使用できます。たとえば、このようなメール送信者サービスを共有できます:

share() $container['mailer'] = $container->share(function ($c) { return new Mailer($c['smtp']); });サービスをPimpleで拡張できますか?

はい、

メソッドを使用して、Pimpleでサービスを拡張できます。これにより、サービスを定義した後に変更することができます。たとえば、このようなメール送信者サービスを拡張して、構成を追加できます。

extend()

この例では、メソッドは、パラメーターとして

サービスを使用してメール送信者サービスで呼び出されます。 $container['mailer'] = $container->extend('mailer', function ($mailer, $c) { $mailer->setFrom($c['email.from']); return $mailer; });

にきびのパラメーターを保護する方法は?

setFrom() in pimpleでは、email.fromメソッドを使用してパラメーターを保護できます(サービスのパラメーターと見なされるべきではありません)。これにより、サービスをサービスの定義として扱うことなく、コンテナに値を保存できます。たとえば、次のような構成値を保護できます:

プロジェクトでPimpleを使用する方法は?

protect()PimpleContainerクラスの新しいインスタンスを作成し、そこでサービスを定義することにより、プロジェクトでPimpleを使用できます。その後、アプリケーションで必要なコンテナからサービスにアクセスできます。これにより、中央集中型の方法でサービスを管理し、アプリケーションのさまざまな部分に注入できます。 $container['config.value'] = $container->protect(function () { return 'value'; });

にきびを使用することの利点は何ですか?

Pimpleは、PHP開発に多くの利点を提供します。集中型の方法でサービスを管理できるため、コードがより柔軟になります。コードは、アプリケーション全体でサービスを共有できるため、再利用を容易にします。テストのためにモックサービスを注入できるため、コードがテストを容易にします。 Pimpleを使用することにより、コードの品質を向上させ、維持とテストを容易にすることができます。

以上がPHPマスター|にきびによる依存噴射の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。