2016-11-27 209 views
0

當使用依賴注入時,是否應該將依賴關係分別傳遞給構造函數,還是可以通過整個DI容器?依賴注入 - 注入容器還是個人依賴?

例如...我有一個名爲'UserRepository'的存儲庫。它包含以下方法:

<?php 

namespace MyApp\Repositories; 

use \MyApp\Models\User; 

class UserRepository { 

    private $ci; 

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

    public function hashPassword($password) 
    { 
     return password_hash($password, PASSWORD_BCRYPT, [ 
      'cost' => 15 
     ]); 
    } 

    public function create($firstname, $lastname, $email, $password) 
    { 
     $user = User::create([ 
      'firstname' => $firstname, 
      'lastname' => $lastname, 
      'email'  => $email, 
      'password' => $this->hashPassword($password) 
     ]); 

     return $user; 
    } 

    public function activateUser($userID) 
    { 
     $user = User($userID); 
     $user->email_verified = 1; 
     $user->save(); 

     $verification = $user->verification(); 
     $verification->is_used = 1; 
     $verification->validated_at = $this->ci->get('Carbon')::now(); 
     $verification->save(); 
    } 
} 

Carbon扶養可用,因爲我已經在Pimple容器通過。我可以通過這種方式訪問​​任何依賴項(只要它們已註冊)。

我使用的是Slim3,它促進了這種類型的DI。但是,在像Laravel這樣的應用程序中,我看到依賴關係被單獨傳遞給構造函數。

有什麼建議嗎?

+0

當您將整個DI容器作爲依賴關係傳遞時,您稱之爲「服務定位器」,並且是的,這是一種不好的做法。 – Federkun

+0

@Federkun謝謝,這是有道理的。我相信疙瘩是一個服務定位器,所以現在我堅持這一點。我不知道兩者是不同的。看來我並不是唯一一個感到困惑的人:https://www.reddit.com/r/PHP/comments/3x9e48/service_locator_dependency_injection/ – BugHunterUK

+0

不,Pimple不是服務定位器,但是_you可以將它用作Service Locator_ – Federkun

回答

2

當您將依賴注入容器傳遞給一個類時,將其稱爲「服務定位器」。使用服務定位器,您的類是仍然負責實例化其依賴關係,因此您也應該單元測試它。但是如何?沒有服務定位器,您的對象就不能存在,並且測試它並不容易。如果你將依賴關係傳遞給構造函數,你可以嘲笑它們。

在你的類你有這樣的:

$verification->validated_at = $this->ci->get('Carbon')::now(); 

其中Carbon是服務名稱。現在您應該記住,您向該類注入的服務定位器需要具有該名稱的服務,並且它應返回Carbon\Carbon類的實例。如果您的服務定位器缺少Carbon服務,或者如果它返回一個完全不同的對象會怎麼樣?你應該是這樣的測試,以確保不破壞任何東西:

$this->assertInstanceOf(Carbon\Carbon::class, $container->get('Carbon')); 

,更重要的是,如果你想重用你的對象別的地方,你需要實現特定的服務定位器實現。

通過使用DIC你的對象是不負責了實例化其依賴:

$container['user.repository'] = function ($c) { 
    return new UserRepository($c['Carbon']); 
}; 

你的類的,更可重複使用和寫作測試是更容易。

+0

很好的解釋。最後一部分讓我感到困惑。在我的情況下,我有'dependencies.php'文件。在你最後一個例子'user.repository'中,我有一個類似的設置。我有一個'Logger'容器,它返回一個新的'Monolog'實例。但是,我仍然使用'$ this-> ci-> get('Logger');'從Services或Actions中訪問它們。我應該以另一種方式訪問​​Logger嗎? – BugHunterUK

+1

不要誤解我,服務定位器不是反模式,當我編寫symfony的控制器時,我經常使用它。當然,它隱藏了依賴關係,並不是最佳實踐,但它是實現這一目標的實用方法。在有意義的地方使用它 – Federkun