Skip to content

Instantly share code, notes, and snippets.

@Albert221
Created April 23, 2018 22:32
Show Gist options
  • Save Albert221/08ca840a13b5865c7aa6ba156495f9b9 to your computer and use it in GitHub Desktop.
Save Albert221/08ca840a13b5865c7aa6ba156495f9b9 to your computer and use it in GitHub Desktop.
Dependency Injection Principle

Dajmy dwa scenariusze, niepodąrzający za DIP i taki z nim zgodny. Na początek klasa którą będziemy chcieli przetestować:

<?php

class Authenticator
{
    private $userRepository;

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

    public function authenticate(string $username, string $password): bool
    {
        $user = $this->userRepository->findByUsername($username);

        // Na potrzeby przykładu hasło nie jest hashowane.
        if ($user !== null && $user->password == $password) {
            // Ogarnij jakąś sesje, jakieś dane etc.
            return true;
        }

        return false;
    }
}

I teraz pierwsza implementacja, niezgodna z DIP:

<?php

class UserRepository
{
    private $pdo;
 
    public __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }
 
    public function findByUsername(string $username): ?User
    {
        // Zrób prepared statement z pdo, zbinduj nazwę użytkownika
        // i zwróć wynik lub nulla jeżeli nie istnieje.
    }
}

Jeżeli będziesz chciał to przetestować, to będziesz musiał zapewnić dla Authenticatora klasę UserRepository, która to będzie potrzebowała PDO, a to wymaga od Ciebie bazy danych... i tak dalej. Złe!

Natomiast podejście oddzielające warstwy abstrakcji wyglądałoby tak:

<?php

interface UsersRepository
{
    public function findByUsername(string $username): ?User;
}

class PDOUsersRepository implements UsersRepository
{
    // I tutaj możesz sobie korzystać z PDO
}

class InMemoryUsersRepository implements UsersRepository
{
    // Ooo, specjalnie na potrzeby testów repozytorium które działa tylko w pamięci? :)
}

I w tym miejscu Twój Authenticator nie jest już zależny od tego w jaki sposób pobierane są dane użytkownika. Jest zależny tylko od repozytorium, którego implementacja jest całkowicie dowolna i nie interesuje Twojego Authenticatora. Takie repozytorium w testach możesz mockować albo dostarczać jakieś specjalnie przeznaczone dla testów, jak np. InMemoryUsersRepository z przykładu wyżej.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment