Ok, więc wczoraj rozmawialiśmy z innymi ludźmi ze społeczności Magento na temat bezpośredniego wykorzystania ObjectManager
klas / szablonów .
Jestem już świadomy powodów, dla których nie powinniśmy bezpośrednio używać ObjectManager, cytując Alana Kenta :
Jest kilka powodów. Kod będzie działał, ale najlepiej jest nie odwoływać się bezpośrednio do klasy ObjectManager.
- Ponieważ tak mówimy! ;-) (lepiej wyrażony jako spójny kod to dobry kod)
- W przyszłości kod może być używany z inną strukturą wstrzykiwania zależności
- Testowanie jest łatwiejsze - przekazujesz fałszywe argumenty dla wymaganej klasy, bez konieczności podawania próbnego menedżera obiektów ObjectManager
- Utrzymuje jaśniejsze zależności - oczywiste jest, od czego zależy kod za pośrednictwem listy konstruktorów, a nie ukrywanie zależności w środku kodu
- Zachęca programistów do lepszego myślenia o koncepcjach takich jak enkapsulacja i modularyzacja - jeśli konstruktor się powiększy, być może jest to znak, że kod wymaga refaktoryzacji
Z tego, co widziałem w StackExchange, wiele osób wybiera proste / krótkie / niezalecane rozwiązanie, na przykład coś takiego:
<?php
//Get Object Manager Instance
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
//Load product by product id
$product = $objectManager->create('Magento\Catalog\Model\Product')->load($id);
Zamiast przechodzić przez bolesny, ale zalecany proces :
- tworzenie modułu
- deklarowanie preferencji
- wstrzykiwać zależności
- zadeklarować metodę publiczną
Jednak i tu pojawia się dylemat, podstawowe pliki Magento 2 często wywołują bezpośrednio ObjectManager . Szybki przykład można znaleźć tutaj: https://github.com/magento/magento2/blob/develop/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php#L57
Oto moje pytania:
- Dlaczego Magento robi to, czego od nas nie zaleca? Czy to oznacza, że istnieją przypadki, w których powinniśmy użyć
ObjectManager
bezpośrednio ? Jeśli tak, jakie to są przypadki? - Jakie są konsekwencje bezpośredniego korzystania z ObjectManager ?
źródło
The intent of zend-servicemanager is for use as an Inversion of Control container. It was never intended as a general purpose service locator [...]
. Dotyczy to również M2. Sprawdź takżeThere are valid use cases
sekcję, która również tutaj dotyczy.Odpowiedzi:
Nie należy bezpośrednio używać ObjectManager!
Wyjątkiem od reguły są:
__wakeup
,serialize
itpźródło
Brutalna odpowiedź: M2 to port M1 - nie jest to kompletne przepisanie. Nie zakładaj więc, że cały kod M2 jest jeszcze doskonale przeniesiony (niestety). To, że znajdziesz coś w bazie kodu M2, nie oznacza, że „jest to najlepszy sposób na zrobienie tego”. Czasami jest to po prostu „jeszcze nie udało się tego naprawić”.
Mniej brutalny: tak jak w przypadku innych odpowiedzi, czasami MUSISZ go użyć, ponieważ nie ma alternatywy. Innym razem może to wynikać z kompatybilności wstecznej. A kod frameworka czasami ma sens z jego bezpośrednim użyciem, ponieważ jest to kod frameworka. Ale gdybym musiał zgadywać bez patrzenia na kod, wiele naprawdę powinno zostać naprawionych, ale nie był jeszcze wystarczająco wysoki priorytet, aby to zrobić.
Pamiętaj tylko o dobrych radach dla rodziców: „Dzieci, róbcie to, co mówię, a nie to, co robię!”
źródło
Nigdy nie powinieneś używać
\Magento\Framework\App\ObjectManager::getInstance()
.To przeczy celowi wstrzykiwania zależności. Wróciliśmy do
Mage::getModel()
.Menedżer obiektów powinien być używany tylko w fabrykach, a następnie wprowadzany do konstruktora.
Zaletą korzystania z tego jest mniej kodu do pisania. Ale to nie sprawia, że jest OK.
Fakt, że jest on nadal używany w rdzeniu, ponieważ nie został jeszcze refaktoryzowany. Mam nadzieję, że będzie.
źródło
di.xml
do stworzenia mapy nazw klas => i wstrzykujesz tę mapę do konstruktora fabryki, a następnie używasz fabryki do tworzenia instancji klasy za pomocą menedżera obiektówNie znając pełnej historii, zgaduję:
Podczas rozwoju M2 zespół Magento w pewnym momencie zabrakło zautomatyzowany skrypt, który zastąpił wystąpień
Mage:getModel()
,Mage::getSingleton()
,$layout->createBlock()
itp używać ObjectManager.Później refaktoryzacja powinna była to naprawić, aby zamiast tego użyć właściwego wstrzykiwania zależności, ale nie było wystarczająco dużo czasu / zasobów, aby przekonwertować wszystkie wystąpienia.
Ostatnio zespół Magento wydaje się używać tego jako mechanizmu ucieczki. Zamiast przerywać istniejącą implementację (poprzez konieczność zmiany konstruktora), po prostu ukrywają nową zależność za pomocą ObjectManager. Nie mogę powiedzieć, że zgadzam się z tym podejściem - pisząc gorszy kod, aby uniknąć złamania BC.
Myślę, że twoje pytanie zawiera już wystarczające powody. Generalnie tworzy ukrytą zależność, innymi słowy, zależność jest w szczegółach implementacji i nie jest widoczna dla samego konstruktora.
źródło
Nie należy używać bezpośrednio Menedżera obiektów!
Na przykład:
także jeśli pracujesz z obserwatorami zdarzeń lub wtyczkami, nigdy nie powinieneś używać go bezpośrednio.
Możesz użyć go w Fabrykach, ale oprócz tego, że najpierw powinieneś wstrzyknąć Menedżer obiektów do Konstruktora, możesz użyć jego obiektu w swojej metodzie
Preferowane użycie:
1) zadeklaruj obiekt prywatny:
2) wstrzyknąć konstruktor i zainicjować:
3) użyj w jakiejś metodzie:
źródło
::getInstance()
Głównym powodem, dla którego programiści są mocno zniechęceni do bezpośredniego korzystania z Menedżera obiektów, jest to, że bezpośrednie użycie Menedżera obiektów powoduje, że rozszerzenia nie można zainstalować w trybie kompilacji.
W związku z tym dla klientów korzystających z trybu zwolnienia, w tym wszystkich klientów korzystających z Magento Cloud, przestaje działać.
Wygląda na to, że dość duży odsetek programistów (około 75%) nie testuje swoich rozszerzeń, aby sprawdzić, czy można je zainstalować w trybie wydania, więc nie napotykaj problemów związanych z nieprawidłowym użyciem ObjectManager.
Od 2017 r. Magento Marketplace przeprowadza test kompilacji i instalacji na wszystkich sprzedawanych za jego pomocą rozszerzeniach. Jeśli twoje rozszerzenie korzysta bezpośrednio z Object Managera, nie przejdzie tych testów i zostanie odrzucone z Marketplace, dopóki nie rozwiążesz tego problemu i przeładujesz.
źródło
Możesz spróbować, tworząc obiekt objectManager i nie powinieneś bezpośrednio używać objectManager .
Użyj czegoś takiego jak
źródło