2013-01-21 15 views
8

Właśnie zaczynamy podejmować skoordynowane wysiłki w celu równomiernego wykorzystania wtyczki zależności w naszym projekcie, a ja natknąłem się na problem.Wstrzyknięcie zależności od PHP, gdy argumenty konstruktora są niedostępne.

Piszę klasę do obsługi zapytań MongoDB. Przepuszczam MongoClient jako zależność od konstruktora, bez problemu. Ale jak radzić sobie z zależnością, gdy zmienna niezbędna do utworzenia obiektu nie jest dostępna w momencie tworzenia?

W szczególności mamy wrapper dla metody MongoCollection, findOne, że jeśli wpiszesz łańcuch, obecnie (w starym kodzie) zamienia go na MongoId z "nowym MongoId (identyfikator $ _)", i używa go do funkcji wyszukiwania.

Z tego, co dowiedziałem się o wstrzyknięciu zależności, posiadanie "nowego MongoId" jest złym pomysłem i już wiem, że utrudni to pisanie przypadków testowych dla funkcji, która konwertuje ciąg na MongoId.

Ale jak obsługiwać wstrzyknięcia, gdy klasa MongoId przyjmuje ciąg identyfikator na konstruktorze?

Jedyną rzeczą, myślałem o tym, że praca jest przekazać w zamknięciu w konstruktorze klasy, która robi coś takiego:

$getMongoId = function($id){ 
    return new MongoId($id); 
}; 

z

class MyMongo 
{ 
    function __construct(MongoClient $client, Closure $mongoIdGetter){...} 
} 

[edytowane, aby to naprawić ostatnia część]

Ale czy to jest właściwy sposób, aby sobie z tym poradzić? Oczywiście, jeśli używamy DiC, możemy to zrobić, ale wymaganie zamknięcia dla konstruktora wydaje się być trochę zbyt duże. Czy jestem po prostu zbyt dogmatyczny odnośnie wstrzykiwania moich zależności? Mógłbym to naprawić łatwo za pomocą "nowego MongoId ($ _ id)" w nowej klasie, jak przypuszczam.

Odpowiedz

1

Ale jak radzić sobie z zależnością, gdy zmienna niezbędna do utworzenia obiektu nie jest dostępna w momencie tworzenia?

PHP zakończy się błędem, zanim będziesz miał szansę sobie z nim poradzić. Jeśli użyjesz parametrów typu i/lub nie określisz ich jako domyślnie, domyślnie, null PHP spowoduje błąd krytyczny, gdy parametr ten nie zostanie przekazany do żadnej funkcji.

Od czego się nauczyłem o wstrzykiwania zależności, mając „nowy MongoId” jest złym pomysłem, i wiem już, że będzie to utrudnić do pisania przypadków testowych dla funkcji, które konwertuje ciąg do MongoId .

Czy to (w PHPUnit)?

$this->assertInstanceOf('\MongoId', $getMongoId($id_string)); 

ale jak mam poradzić sobie zastrzyk, gdy klasa MongoId wykonuje ciąg ID na konstruktora?

Nie rozumiem, co masz na myśli, ale powinieneś testować tylko wynik przetwarzania MongoId.

Ostatnia część twojego pytania trochę mnie traci, myślę, że tak jest, ponieważ nie jest to prawdziwy PHP (czyli $__construct).

Nie jestem pewien, dlaczego musisz wrzucić tę funkcję do klasy. Mam na myśli to, co mam większość czasu jest:

function findById($id){ 
    if(!$id instanceof \MongoId) $id = new MongoId($id); 
    return $this->getCollection()->findOne($id); 
} 

Nie trzeba niczego więcej niż to i nie trzeba przetestować konstruktora MongoId od przetestowany, który został już urządzenie powinno być zamiast jednostka testowanie TWOJEGO publicznego API, a nie kogoś innego.

+0

Dzięki - konstrukcja $ __ była po prostu mózgowym pierdnięciem, naprawionym powyżej. Myślę, że częściowo błędnie przeczytałeś moje pytanie, ponieważ kiedy mówię "uchwyt" powyżej, nie mówię o obsłudze błędów, tylko o ogólnym znaczeniu tego słowa. – Karptonite

+0

@Karptonite Oh ok, więc możesz wyjaśnić, dlaczego chcesz ustawić konstruktor MongoId w konstrukcie, rozumiem zależność, ale nie będzie to potrzebne, dopóki nie użyjesz funkcji 'find'. Chodzi mi o to, że do testowania jednostkowego wystarczy, że sprawdzisz odpowiedź funkcji publicznej, że zwraca dokument, który powinien istnieć podczas wprowadzania ciągu znaków dla '_id', nie powinieneś rozszerzać testów jednostkowych na sam sterownik MongoDB. – Sammaye

+0

Jestem nowy w zastrzyku zależności - ale zrozumiałem, że używanie funkcji, jaką napisałeś, z "nowym MongoId" w samym kodzie, było generalnie złym pomysłem - na przykład, jeśli użyłem jakiejkolwiek metody MongoId w moim nie mogłem z niego kpić, aby mój kod poprawnie nazywał te metody. Oczywiście, nie jest to coś, co teraz robię. – Karptonite

2

Zamiast zamknięcia można użyć fabryczne:

class MongoFactory 
{ 
    public function createMongoDb($id) 
    { 
     return new MongoId($id); 
    } 
} 

w fabrykach jest traktowane dobrze mieć „nowe coś” zakodowanego zależności ponieważ tworzenie obiektów jest ich jedynym celem i można łatwo wymienić je z inną Fabryką.

Twoja klasa klientów (MyMongo) będzie teraz zależna od MongoFactory (lub jej interfejsu, jeśli zechcesz), którą możesz z łatwością "wstrzyknąć".

Powiązane problemy