Итак, вчера у нас была большая беседа с другими людьми из сообщества Magento относительно прямого использования ObjectManager
в классах / шаблонах .
Мне уже известны причины, по которым мы не должны использовать ObjectManager напрямую, цитируя Алана Кента :
Есть несколько причин. Код будет работать, но лучше не ссылаться на класс ObjectManager напрямую.
- Потому что мы так говорим! ;-) (лучше выражать как непротиворечивый код - хороший код)
- Код может быть использован с другой структурой внедрения зависимостей в будущем
- Тестирование проще - вы передаете фиктивные аргументы для требуемого класса, не предоставляя фиктивный ObjectManager
- Это делает ясность зависимостей - очевидно, от чего зависит код через список конструкторов, вместо того, чтобы скрывать зависимости в середине кода
- Это побуждает программистов лучше продумывать такие понятия, как инкапсуляция и модульность - если конструктор становится большим, возможно, это знак того, что код нуждается в рефакторинге
Из того, что я видел в StackExchange, многие люди склонны выбирать простое / короткое / не рекомендуемое решение, например, что-то вроде этого:
<?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);
Вместо того, чтобы пройти болезненный, но рекомендуемый процесс :
- создание модуля
- декларирование предпочтений
- вводить зависимости
- объявить публичный метод
Однако, здесь возникает дилемма: файлы ядра Magento 2 часто вызывают ObjectManager напрямую . Быстрый пример можно найти здесь: https://github.com/magento/magento2/blob/develop/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php#L57
Итак, вот мои вопросы:
- Почему Magento делает то, что они рекомендуют нам не делать? Означает ли это, что в некоторых случаях мы должны использовать
ObjectManager
напрямую ? Если так, то каковы эти случаи? - Каковы последствия использования ObjectManager напрямую ?
источник
The intent of zend-servicemanager is for use as an Inversion of Control container. It was never intended as a general purpose service locator [...]
. Что касается и М2 тоже. Также проверьтеThere are valid use cases
раздел, который, опять же, применяется и здесь.Ответы:
Вы не должны использовать ObjectManager напрямую!
Исключением из правила являются:
__wakeup
,serialize
и т. д.источник
Брутальный ответ: M2 - это порт M1, а не полная перезапись. Так что не думайте, что весь код M2 прекрасно перенесен (к сожалению). Просто потому, что вы найдете что-то в базе кода M2, это не означает «это лучший способ сделать это». Иногда это просто «мы еще не успели это исправить».
Менее жестокий: Как и в других ответах, иногда вы ДОЛЖНЫ использовать его, так как альтернативы нет. В других случаях это может быть связано с обратной совместимостью. И фреймворковый код иногда имеет смысл использовать его напрямую, потому что это фреймворковый код. Но если бы мне пришлось угадывать, не глядя на код, многие действительно должны быть исправлены, но это еще не было достаточно высоким приоритетом, чтобы сделать это.
Просто помните хороший совет для родителей: «Дети, делайте то, что я говорю, а не то, что я делаю!»
источник
Вы никогда не должны использовать
\Magento\Framework\App\ObjectManager::getInstance()
.Это побеждает цель введения зависимости. Мы вернулись в
Mage::getModel()
.Диспетчер объектов должен использоваться только на фабриках, а затем вводиться в конструктор.
Преимущество использования этого заключается в меньшем количестве кода для записи. Но это не делает это хорошо.
Факт, что это все еще используется в ядре, потому что это еще не подверглось рефакторингу. Я надеюсь, что это будет.
источник
di.xml
для создания карты имени ключа => и внедряете эту карту в конструктор фабрики и используете фабрику для создания экземпляра класса через objectmanagerНе зная полной истории, вот мое предположение:
При разработке М2 команда Magento на каком - то этапе побежала автоматизированный скрипт , который заменил вхождения
Mage:getModel()
,Mage::getSingleton()
,$layout->createBlock()
и т.д. , чтобы использовать ObjectManager.Более поздний рефакторинг должен был исправить это, чтобы вместо этого использовать правильное внедрение зависимостей, но не было достаточно времени / ресурсов для преобразования всех вхождений.
Также в последнее время команда Magento, похоже, использует это как механизм побега. Вместо того, чтобы ломать существующую реализацию (нужно изменить конструктор), они просто скрывают новую зависимость через ObjectManager. Я не могу сказать, что согласен с таким подходом - писать худший код, чтобы избежать разрыва BC.
Я думаю, что ваш вопрос уже включает в себя достаточно причин. Обычно это создает скрытую зависимость, другими словами, зависимость находится в деталях реализации и не видна только из конструктора.
источник
Не следует использовать диспетчер объектов напрямую!
Например:
также, если вы работаете с наблюдателями событий или плагинами, вы никогда не должны использовать его напрямую.
Вы можете использовать его на фабриках, но за исключением того, что сначала вы должны внедрить диспетчер объектов в конструктор, затем вы можете использовать его объект в своем методе.
Предпочитают использовать:
1) объявить приватный объект:
2) внедрить в конструктор и инициализировать:
3) использовать в некотором методе:
источник
::getInstance()
Основная причина, по которой разработчикам настоятельно не рекомендуется использовать диспетчер объектов напрямую, заключается в том, что прямое использование диспетчера объектов приводит к невозможности установки расширения в режиме скомпилированного выпуска.
Таким образом, он работает для ваших клиентов, использующих режим выпуска, в том числе для всех пользователей Magento Cloud.
Кажется, что довольно большая часть разработчиков (примерно 75%) не тестирует свои расширения, чтобы посмотреть, могут ли они быть установлены в режиме выпуска, поэтому не сталкивайтесь с проблемами, вызванными неправильным использованием ObjectManager.
Начиная с 2017 года, Magento Marketplace запускает тест на компиляцию и установку всех расширений, продаваемых через него. Если ваше расширение напрямую использует диспетчер объектов, оно не пройдёт эти тесты и будет отклонено из Marketplace, пока вы не решите эту проблему и не загрузите заново.
источник
Вы можете попробовать создать объект objectManager и не следует использовать objectManager напрямую .
Используйте что-то вроде
источник