目錄
什麼是Pimple,為什麼在PHP中使用它?
Pimple是如何工作的?
如何安裝Pimple?
如何在Pimple中定義服務?
如何在Pimple中訪問服務?
如何在Pimple中共享服務?
我可以在Pimple中擴展服務嗎?
如何保護Pimple中的參數?
如何在一個項目中使用Pimple?
使用Pimple的好處是什麼?
首頁 後端開發 php教程 PHP主|用丘疹注入依賴

PHP主|用丘疹注入依賴

Feb 24, 2025 am 08:57 AM

PHP Master | Dependency Injection with Pimple

核心要點

  • 依賴注入是應用開發中的一個關鍵概念,通過將依賴項注入模塊而不是硬編碼它們,可以編寫更高效、更易維護的代碼。
  • Pimple是一個簡單的依賴注入容器,它使用PHP的閉包以可管理的方式定義依賴項,有助於保持代碼的可維護性。
  • 注入依賴項的兩種主要技術是基於構造函數的依賴注入和基於設置器的注入,每種技術都有其自身的優缺點。
  • Pimple通過充當定義依賴項的容器來支持軟件開發的DRY(不要重複自己)原則,避免重複,從而更輕鬆地管理和集中應用程序中的服務。
  • Pimple還提供高級功能,例如使用共享對象返回相同實例的能力,以及無需影響原始實現即可動態修改現有閉包的能力。

在應用程序開發中,我們嘗試創建獨立的模塊,以便在未來的項目中重用代碼。但是,創建提供有用功能的完全獨立的模塊很困難;除非正確管理它們的依賴關係,否則它們可能會導致維護噩夢。這就是依賴注入派上用場的地方,因為它使我們能夠注入代碼正常運行所需的依賴項,而無需將它們硬編碼到模塊中。 Pimple是一個簡單的依賴注入容器,它利用PHP的閉包以可管理的方式定義依賴項。在本文中,我們將探討硬編碼依賴項的問題,依賴注入如何解決這些問題,以及如何使用Pimple來使利用依賴注入的代碼更易於維護。

具體依賴項的問題

在編寫應用程序時,我們會使用許多PHP類。一個類可能需要調用一個或多個其他類的方法來提供預期的功能,因此我們說第一個類依賴於其他類。例如:

<?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}
登入後複製
登入後複製
登入後複製
登入後複製

類A依賴於類B。如果類B不可用,則上述代碼將無法工作。此外,每次我們在類中硬編碼對象的創建時,我們都會對該類產生具體的依賴關係。具體依賴關係是編寫可測試代碼的障礙。更好的方法是向類A提供類B的對象。這些對象可以通過A的構造函數或setter方法提供。在我們進一步討論之前,讓我們來看一個更現實的場景。

如今,在社交網絡網站上共享內容非常普遍,大多數網站都在其網站上直接顯示其社交資料提要。假設我們有一個名為SocialFeeds的類,它從Twitter、Facebook、Google 等社交網站生成提要。創建單獨的類來處理這些服務中的每一個。在這裡,我們將研究與Twitter交互的類TwitterService。 SocialFeeds類使用TwitterService請求Twitter提要。 TwitterService與數據庫交互以檢索訪問API的特定用戶令牌。令牌傳遞給OAuth類,該類使用提供的令牌檢索提要並將其返回給SocialFeeds類。

<?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}
登入後複製
登入後複製
登入後複製
登入後複製
<?php
class SocialFeeds
{
    public function getSocialFeeds() {
        $twService = new TwitterService();
        echo $twService->getTweets();
    }
}
登入後複製
登入後複製
登入後複製
<?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);
    }
}
登入後複製
<?php
class OAuth
{
    public function requestTwitterFeed($token) {
        // Retrieve and return twitter feed using the token         
    }
}
登入後複製

很明顯,SocialFeeds依賴於TwitterService。但是TwitterService依賴於DB和OAuth,因此SocialFeeds間接依賴於DB和OAuth。那麼問題是什麼呢? SocialFeeds依賴於三個類的具體實現,因此不可能在沒有其他類的真實實現的情況下單獨測試SocialFeeds。或者,假設我們想使用不同的數據庫或不同的OAuth提供程序。在這種情況下,我們必須在整個代碼中用新類替換現有類。

修復具體依賴項

解決這些依賴項問題的方案很簡單,即在必要時動態提供對象,而無需使用具體實現。有兩種類型的技術可以注入依賴項:基於構造函數的依賴注入和基於設置器的注入。

基於構造函數的注入

使用基於構造函數的依賴注入,依賴對像是在外部創建的,並作為參數傳遞給類的構造函數。我們可以將這些對象分配給類變量,並在類內任何地方使用。 SocialFeeds類的基於構造函數的注入如下所示:

<?php
class DB
{
    public function getQueryResults($query) {
        // Get results from database and return token
    }
}
登入後複製

TwitterService的實例作為對像傳遞給構造函數。 SocialFeeds仍然依賴於TwitterService,但現在我們可以自由地提供不同版本的Twitter服務提供程序,甚至可以提供用於測試目的的模擬對象。關於TwitterService,DB和OAuth類也以類似的方式定義。

<?php
class SocialFeeds
{
    public $twService;

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

    public function getSocialFeeds() {
        echo $this->twService->getTweets();
    }
}
登入後複製

基於設置器的注入

使用基於設置器的注入,對像是通過setter方法而不是構造函數提供的。以下是SocialFeeds類的基於設置器的依賴注入實現:

<?php
$db = new DB();
$oauth = new OAuth();
$twService = new TwitterService($db, $oauth);
$socialFeeds = new SocialFeeds($twService);
$socialFeeds->getSocialFeeds();
登入後複製

現在包括DB和OAuth的初始化代碼如下所示:

<?php
class SocialFeeds
{
    public $twService;

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

    public function setTwitterService($twService) {
        $this->twService = $twService;
    }
}
登入後複製

構造函數與設置器注入

選擇基於構造函數的注入還是基於設置器的注入取決於您。當需要所有依賴項才能實例化類時,基於構造函數的注入是合適的。當並非每次都需要依賴項時,基於設置器的注入是合適的。

優點

  • 構造函數 – 只需查看類的構造函數即可識別類的所有依賴項
  • 設置器 – 添加新的依賴項就像添加新的setter方法一樣簡單,不會破壞現有代碼

缺點

  • 構造函數 – 添加新的依賴項會增加構造函數的參數;需要更新整個應用程序中的現有代碼以提供新的依賴項
  • 設置器 – 我們必須手動搜索必要的依賴項,因為它們沒有在任何地方指定

了解了依賴注入和各種注入技術後,是時候看看Pimple以及它如何融入其中了。

Pimple在DI中的作用

當我們已經可以使用前面提到的技術注入依賴項時,您可能想知道為什麼需要Pimple。要回答這個問題,我們需要看看DRY原則。

不要重複自己(DRY)是軟件開發的一個原則,旨在減少各種信息的重複,這在多層架構中特別有用。 DRY原則的陳述是“每個知識片段都必須在一個系統中具有單個、明確、權威的表示”——維基百科

考慮基於構造函數的注入示例。每次我們想要SocialFeed類的對象時,我們都必須重複實例化和傳遞其依賴項的整個設置過程。根據DRY,應避免此類代碼以防止維護出現問題。 Pimple充當定義此類依賴項以避免重複的容器。讓我們來看一個簡單的例子,看看Pimple是如何工作的。

<?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}
登入後複製
登入後複製
登入後複製
登入後複製

創建Pimple的實例充當存儲依賴項的容器。它實現SPL ArrayAccess接口,因此使用它與使用數組非常相似。首先,我們定義了一個鍵,該鍵保存我們想要的某個任意類的名稱。然後,我們定義了一個閉包來返回指定類的實例,該實例充當服務。請注意,將向$c傳遞容器的實例,因此我們可以根據需要引用其他已定義的鍵;每個已定義的參數或對像都可通過$c變量在閉包中使用。現在,每當我們想要類的實例時,我們都可以引用鍵來檢索對象。讓我們將SocialFeeds示例轉換為Pimple。 Pimple官方網站上的示例顯示了基於構造函數的注入,因此在這裡我們將說明基於設置器的注入。請記住,為了使用Pimple,我們不需要修改前面定義的任何setter方法或代碼——我們只是封裝了邏輯。

<?php
class SocialFeeds
{
    public function getSocialFeeds() {
        $twService = new TwitterService();
        echo $twService->getTweets();
    }
}
登入後複製
登入後複製
登入後複製

DB和OAuth類都是獨立的模塊,因此我們直接在閉包內返回它們的新的實例。然後,我們使用基於設置器的注入向TwitterService類添加依賴項。我們已經將DB和OAuth類添加到容器中,因此我們可以使用$c['db']和$c['oauth']直接在函數內訪問它們。現在,依賴項作為服務封裝在容器內。每當我們想要使用不同的DB類或不同的OAuth服務時,我們只需替換容器語句中的類,一切都會完美運行。使用Pimple,您只需要在一個地方添加新的依賴項。

高級Pimple用法

在上述場景中,Pimple會在每次請求時從閉包返回每個類的新的實例。在某些情況下,我們需要使用相同的對象而無需每次都初始化新的實例,例如連接到數據庫就是一個完美的例子。 Pimple提供了使用共享對象返回相同實例的能力,這樣做需要我們通過share()方法指定閉包,如下所示:

<?php
class A
{
    public function a1() {
        $b = new B();
        $b->b1();
    }
}
登入後複製
登入後複製
登入後複製
登入後複製

此外,到目前為止,我們已經在Pimple容器中的單個位置定義了所有依賴項。但是,考慮一下我們需要具有其依賴項的服務,但配置方式與原始服務略有不同的情況。例如,假設我們需要訪問ORM來實現TwitterService類的某些功能。我們不能更改現有的閉包,因為它會強制所有現有功能使用ORM。 Pimple提供extend()方法來動態修改現有閉包,而不會影響原始實現。考慮以下代碼:

<?php
class SocialFeeds
{
    public function getSocialFeeds() {
        $twService = new TwitterService();
        echo $twService->getTweets();
    }
}
登入後複製
登入後複製
登入後複製

現在,我們能夠在特殊情況下使用tweet_service的不同擴展版本。第一個參數是服務的名稱,第二個參數是一個函數,該函數可以訪問對象實例和容器。實際上,extend()是動態添加依賴項以適應不同情況的強大方法,但請確保將服務的擴展版本限制在最低限度,因為它會增加重複代碼的數量。

總結

管理依賴項是Web應用程序開發中最重要和最困難的任務之一。我們可以使用構造函數和setter方法的依賴注入來有效地管理它們。但是,依賴注入本身也有一些麻煩,Pimple通過提供一個輕量級容器來以DRY的方式創建和存儲對象依賴項來解決這些問題。請隨時在下面的評論中分享您在項目中管理依賴項的經驗,以及您對Pimple作為依賴注入容器的看法。

關於使用Pimple進行依賴注入的常見問題解答 (FAQ)

什麼是Pimple,為什麼在PHP中使用它?

Pimple是一個簡單的PHP依賴注入容器,允許您管理和集中應用程序中的服務。它用於PHP,使代碼更靈活、更可重用和更易於測試。通過使用Pimple,您可以在一個地方實例化對象,然後將它們注入到應用程序的不同部分,從而減少對全局狀態的需求,並使您的代碼更易於維護和測試。

Pimple是如何工作的?

Pimple通過在容器中存儲服務定義來工作。這些定義是可以調用(函數或方法)的,它們返回服務的實例。當您從容器訪問服務時,Pimple會執行服務定義以創建服務對象。這允許您以集中方式管理服務,並在整個應用程序中共享服務。

如何安裝Pimple?

可以使用Composer(PHP的依賴項管理工具)安裝Pimple。您可以在系統上全局安裝Composer,然後通過運行命令composer require pimple/pimple在項目中引入Pimple。

如何在Pimple中定義服務?

在Pimple中,您可以通過將可調用對象分配給容器中的鍵來定義服務。可調用對象應返回服務的實例。例如,您可以像這樣為郵件發送器類定義服務:

$container['mailer'] = function ($c) { return new Mailer($c['smtp']); };

在此示例中,郵件發送器服務定義為Mailer類的新的實例,其中smtp服務作為依賴項注入。

如何在Pimple中訪問服務?

您可以使用帶有服務鍵的數組表示法來訪問Pimple中的服務。例如,您可以像這樣訪問郵件發送器服務:$mailer = $container['mailer'];。當您訪問服務時,Pimple會執行服務定義並返回服務對象。

如何在Pimple中共享服務?

默認情況下,Pimple每次訪問服務時都會返回服務的新的實例。如果您想共享服務並每次返回相同的實例,可以使用share()方法。例如,您可以像這樣共享郵件發送器服務:$container['mailer'] = $container->share(function ($c) { return new Mailer($c['smtp']); });

我可以在Pimple中擴展服務嗎?

是的,您可以使用extend()方法擴展Pimple中的服務。這允許您在定義服務後修改它。例如,您可以像這樣擴展郵件發送器服務以添加其他配置:

$container['mailer'] = $container->extend('mailer', function ($mailer, $c) { $mailer->setFrom($c['email.from']); return $mailer; });

在此示例中,setFrom()方法使用email.from服務作為參數在郵件發送器服務上調用。

如何保護Pimple中的參數?

在Pimple中,您可以使用protect()方法保護參數(不應被視為服務的參數)。這允許您在容器中存儲值,而不會將它們視為服務定義。例如,您可以像這樣保護配置值:$container['config.value'] = $container->protect(function () { return 'value'; });

如何在一個項目中使用Pimple?

您可以通過創建PimpleContainer類的新的實例並在其中定義服務來在一個項目中使用Pimple。然後,您可以在應用程序中需要的地方從容器訪問服務。這允許您以集中方式管理服務並將它們注入到應用程序的不同部分。

使用Pimple的好處是什麼?

Pimple為PHP開發提供了許多好處。它使您的代碼更靈活,因為它允許您以集中方式管理服務。它使您的代碼更易於重用,因為它允許您在整個應用程序中共享服務。它使您的代碼更易於測試,因為它允許您注入模擬服務進行測試。通過使用Pimple,您可以提高代碼質量,並使其更易於維護和測試。

以上是PHP主|用丘疹注入依賴的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1662
14
CakePHP 教程
1418
52
Laravel 教程
1311
25
PHP教程
1261
29
C# 教程
1234
24
說明PHP中的不同錯誤類型(注意,警告,致命錯誤,解析錯誤)。 說明PHP中的不同錯誤類型(注意,警告,致命錯誤,解析錯誤)。 Apr 08, 2025 am 12:03 AM

PHP中有四種主要錯誤類型:1.Notice:最輕微,不會中斷程序,如訪問未定義變量;2.Warning:比Notice嚴重,不會終止程序,如包含不存在文件;3.FatalError:最嚴重,會終止程序,如調用不存在函數;4.ParseError:語法錯誤,會阻止程序執行,如忘記添加結束標籤。

PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

說明PHP中的安全密碼散列(例如,password_hash,password_verify)。為什麼不使用MD5或SHA1? 說明PHP中的安全密碼散列(例如,password_hash,password_verify)。為什麼不使用MD5或SHA1? Apr 17, 2025 am 12:06 AM

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

什麼是HTTP請求方法(獲取,發布,放置,刪除等),何時應該使用? 什麼是HTTP請求方法(獲取,發布,放置,刪除等),何時應該使用? Apr 09, 2025 am 12:09 AM

HTTP請求方法包括GET、POST、PUT和DELETE,分別用於獲取、提交、更新和刪除資源。 1.GET方法用於獲取資源,適用於讀取操作。 2.POST方法用於提交數據,常用於創建新資源。 3.PUT方法用於更新資源,適用於完整更新。 4.DELETE方法用於刪除資源,適用於刪除操作。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP如何安全地上載文件? PHP如何安全地上載文件? Apr 10, 2025 am 09:37 AM

PHP通過$\_FILES變量處理文件上傳,確保安全性的方法包括:1.檢查上傳錯誤,2.驗證文件類型和大小,3.防止文件覆蓋,4.移動文件到永久存儲位置。

解釋self ::,parent ::和static :: in php oop中的區別。 解釋self ::,parent ::和static :: in php oop中的區別。 Apr 09, 2025 am 12:04 AM

在PHPOOP中,self::引用當前類,parent::引用父類,static::用於晚靜態綁定。 1.self::用於靜態方法和常量調用,但不支持晚靜態綁定。 2.parent::用於子類調用父類方法,無法訪問私有方法。 3.static::支持晚靜態綁定,適用於繼承和多態,但可能影響代碼可讀性。

See all articles