Magento 2: Den ObjectManager direkt verwenden oder nicht?


134

Ok, also gestern hatten wir ein großes Gespräch mit anderen Leuten aus der Magento-Community über die direkte Verwendung der ObjectManagerin Klassen / Vorlagen .

Ich kenne bereits die Gründe, warum wir den ObjectManager nicht direkt verwenden sollten, unter Berufung auf Alan Kent :

Es gibt verschiedene Gründe. Der Code funktioniert, es wird jedoch empfohlen, die ObjectManager-Klasse nicht direkt zu referenzieren.

  • Weil wir es so sagen! ;-) (besser ausgedrückt als konsistenter Code ist guter Code)
  • Der Code könnte in Zukunft mit einem anderen Abhängigkeitsinjektionsframework verwendet werden
  • Das Testen ist einfacher - Sie übergeben Scheinargumente für die erforderliche Klasse, ohne einen Schein-ObjectManager bereitstellen zu müssen
  • Abhängigkeiten bleiben klarer - es ist offensichtlich, wovon der Code über die Konstruktorliste abhängt, anstatt Abhängigkeiten in der Mitte des Codes zu verbergen
  • Es ermutigt Programmierer, Konzepte wie Kapselung und Modularisierung besser zu überdenken - wenn der Konstruktor groß wird, ist es vielleicht ein Zeichen, dass der Code überarbeitet werden muss

Nach dem, was ich in StackExchange gesehen habe, entscheiden sich viele Leute für die einfache / kurze / nicht empfohlene Lösung, zum Beispiel für Folgendes:

<?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);

Anstatt den schmerzhaften, aber empfohlenen Prozess zu durchlaufen :

  • Erstellen eines Moduls
  • Präferenzen angeben
  • Abhängigkeiten einschleusen
  • Deklarieren Sie eine öffentliche Methode

Und hier kommt das Dilemma, dass Magento 2-Kerndateien den ObjectManager oft direkt aufrufen . Ein kurzes Beispiel finden Sie hier: https://github.com/magento/magento2/blob/develop/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php#L57

Also hier sind meine Fragen:

  • Warum macht Magento das, wovon sie uns raten? Heißt das, es gibt einige Fälle, in denen wir die ObjectManagerdirekt verwenden sollten ? Wenn ja, wie lauten diese Fälle?
  • Welche Konsequenzen hat die direkte Verwendung des ObjectManagers ?

4
Schauen Sie sich das an: magento.stackexchange.com/q/28617/146
Marius

3
Relevanter Link: mwop.net/blog/2016-04-26-on-locators.html . Das relevante Stück davon wäre The intent of zend-servicemanager is for use as an Inversion of Control container. It was never intended as a general purpose service locator [...]. Das gilt auch für M2. Überprüfen Sie auch den There are valid use casesAbschnitt, der auch hier gilt.
nevvermind

3
Es gab einige Zeit der M2-Entwicklung, in der OM bereits vorhanden war, aber das gesamte Magento wurde noch nicht auf Konstruktor-Injection umgestellt. Zu diesem Zeitpunkt haben viele Leute Mage :: getSingleton () durch ObjectManager :: getInstance () -> get () ersetzt. Die meisten dieser Verwendungen wurden zu dieser Zeit eingeführt. Später wurden alle Mage :: getSingleton () -Aufrufe durch Konstruktorinjektion durch ein Tool ersetzt, aber das Tool erkannte ObjectManager :: getInstance () nicht, sodass es nicht durch Konstruktorinjektion ersetzt wurde.
Anton Kril


3
@ TejabhagavanKollepara hast du beide Fragen gelesen? Es gibt ähnliche, aber weit davon entfernt, sich zu duplizieren
Raphael beim Digital Pianism

Antworten:


98

Sie sollten den ObjectManager nicht direkt verwenden!

Ausnahme von der Regel sind:

  • in statischen magischen Methoden wie __wakeup, serializeusw.
  • für den Fall, dass Sie die Abwärtskompatibilität des Konstruktors herstellen sollten
  • im globalen umfeld, wie in einrichtungen des integrationstests.
  • in der Klasse, die nur für die Erstellung von Objekten wie Factory, Proxy usw. benötigt wird

2
Ich weiß, ich sollte es niemals direkt verwenden, aber warum macht Magento das? ^^
Raphael beim Digitalen Pianismus

2
in Ihrem Beispiel ist für die Abwärtskompatibilität
KAndy

Sind diese immer als @deprecated gekennzeichnet?
Raphael bei Digital Pianism


5
Oh ja, Kumpel, ich weiß, es ist nur verwirrend. Vielleicht hätten sie sagen sollen: "
Tu

53

Warum greift M2 manchmal direkt auf den Objektmanager zu, wenn wir davon abraten?

Brutale Antwort: M2 ist ein Port von M1 - kein vollständiges Umschreiben. Gehen Sie also nicht davon aus, dass der gesamte M2-Code (leider) noch perfekt portiert ist. Nur weil Sie etwas in der M2-Codebasis finden, heißt das nicht, dass dies die beste Methode ist. Manchmal ist es nur "wir haben es noch nicht geschafft, es zu reparieren".

Weniger brutal: Wie in anderen Antworten heißt es manchmal, dass Sie es verwenden MÜSSEN, da es keine Alternative gibt. In anderen Fällen kann dies aus Gründen der Abwärtskompatibilität auftreten. Und manchmal ist es sinnvoll, Framework-Code direkt zu verwenden, da es sich um Framework-Code handelt. Aber wenn ich raten müsste, ohne auf Code zu achten, sollten viele wirklich repariert werden, aber die Priorität war noch nicht hoch genug, um dies zu tun.

Denken Sie nur an den guten Rat der Eltern: "Kinder, tun Sie, was ich sage, nicht was ich tue!"


9
exzellentes Zitat: Kinder, tut was ich sage, nicht was ich tue!
Sivakumar

So funktioniert es nicht, Kiddo
Ansyori

Gibt es eine von Magento 2 empfohlene Möglichkeit, ein Problem mit weichen Abhängigkeiten ohne Objektmanager zu haben? Ich habe ein Modul mit einer weichen Abhängigkeit von einem anderen (es lädt eine andere Klasse, wenn das Modul existiert). Ich kann nicht DI diese Klasse, weil dann DI fehlschlagen wird. Ich kann nicht einmal eine Fabrik für diese Klasse DI, weil die Fabrik DI nicht kann.
Nathan Merrill

50

Sie sollten niemals verwenden \Magento\Framework\App\ObjectManager::getInstance().
Es besiegt den Zweck der Abhängigkeitsinjektion. Wir sind zurück bei Mage::getModel().
Der Objektmanager sollte nur in Fabriken und dann wie in einem Konstruktor injiziert verwendet werden.

Der Vorteil dieser Methode ist, dass weniger Code geschrieben werden muss. Aber das macht es nicht OK.
Die Tatsache, dass dies immer noch im Kern verwendet wird, liegt daran, dass es noch nicht überarbeitet wurde. Ich hoffe es wird.


5
Wir sind uns also einig, dass Magento-Code es falsch macht, oder?
Raphael bei Digital Pianism

11
richtig. Sie liegen falsch :).
Marius

Ich glaube nicht, dass sie falsch verwenden. Sie setzen es bei Bedarf ein: wenn eine dynamische Auflösung erforderlich ist (insbesondere Plugins) und wenn BC auf sofort veralteten Methoden bleibt.
Nevvermind

2
@nevvermind Mit einer Fabrik. Sie di.xmlerstellen mit eine key => class name map und fügen diese Map in den Konstruktor der Factory ein und verwenden die Factory, um die Klasse über objectmanager zu instanziieren
Marius

2
@nevvermind Die Meinung eines Magento-Mitarbeiters steht jedoch über Ihrer Meinung. Oben haben Sie eine Antwort von KAndy, die in Fettdruck lautet: "Sie sollten den Objektmanager nicht direkt verwenden": magento.stackexchange.com/a/117103/146 .
Marius

22

Warum macht Magento das, wovon sie uns raten? Bedeutet das, dass wir in einigen Fällen den ObjectManager direkt verwenden sollten? Wenn ja, in welchen Fällen?

Ohne die ganze Geschichte hier zu kennen, ist meine Vermutung:

Bei der Entwicklung von M2 das Magento Team irgendwann lief ein automatisiertes Skript , das Vorkommen ersetzt Mage:getModel(), Mage::getSingleton(), $layout->createBlock()etc. , um die Objektmanager zu verwenden.

Späteres Refactoring sollte dies behoben haben, um stattdessen die ordnungsgemäße Abhängigkeitsinjektion zu verwenden, aber es gab nicht genügend Zeit / Ressourcen, um alle Vorkommen zu konvertieren.

Auch das Magento-Team scheint dies in letzter Zeit als Fluchtmechanismus zu nutzen. Anstatt eine vorhandene Implementierung zu beschädigen (indem der Konstruktor geändert werden muss), wird die neue Abhängigkeit einfach über den ObjectManager ausgeblendet. Ich kann nicht sagen, dass ich diesem Ansatz zustimme - schlechteren Code zu schreiben, um einen BC-Bruch zu vermeiden.

Welche direkten Konsequenzen hat die direkte Verwendung des ObjectManagers?

Ich denke, Ihre Frage enthält bereits genügend Gründe. Im Allgemeinen wird eine versteckte Abhängigkeit erstellt, dh die Abhängigkeit befindet sich in den Implementierungsdetails und ist nicht nur für den Konstruktor sichtbar.


Es ist ironisch, denn hätte es dort vor der Veröffentlichung richtig gemacht, wäre das BC überhaupt kein Problem gewesen
Robbie Averill,

12

Sollte Object Manager nicht direkt verwenden!

Zum Beispiel:

\Magento\Framework\App\ObjectManager::getInstance();

Auch wenn Sie mit Ereignisbeobachtern oder Plugins arbeiten, sollten Sie diese niemals direkt verwenden.

Sie könnten es in Fabriken verwenden, aber außer dass Sie den Objekt-Manager zuerst in den Konstruktor einfügen sollten, dann können Sie sein Objekt in Ihrer Methode verwenden

Bevorzugt zu verwenden:

1) privates Objekt deklarieren:

private $_objectManager;

2) füge den Konstruktor ein und initialisiere:

public function __construct(
    \Magento\Framework\ObjectManagerInterface $objectmanager
) {
    $this->_objectManager = $objectmanager;
}

3) Verwenden Sie in irgendeiner Methode:

public function create() {
    return $this->_objectManager->create(/* ......... */);
}

Diese Antwort gilt für die folgenden Versionen von Magento 2.2. Notieren Sie sich dies bitte. Gemäß den neuen Magento 2-Standards können wir jetzt auch keine objectManager-Instanz verwenden. Wir müssen die Factory der Objektklasse oder des Repositorys verwenden, um Daten abzurufen.


Ist es eine gute Praxis, es auf diese Weise zu verwenden?
Enrico69

Ja, da Magento die Verwendung von Direct ObjectManager nicht zulässt, müssen Sie diese Methode verwenden!
Ronak Chauhan

Sie sollten es auch niemals in Events (ich denke, Sie meinen Observers) und Plugins verwenden. Sie sollten die benötigten Objekte injizieren, nicht den ObjectManager. Nur in einer Fabrik können Sie den Objektmanager verwenden und dann sollten Sie in der Tat es injizieren statt telefonieren::getInstance()
7ochem

Richtig, bearbeiten Sie die Antwort @ 7ochem
Ronak Chauhan

Das Abwerten einer Antwort ist nicht angemessen. Wenn Sie über bessere Kenntnisse verfügen, können Sie Ihre eigene Antwort hinzufügen oder die Antwort eines anderen bearbeiten, um eine bessere Vorstellung zu erhalten und anderen zu helfen. @ 7ochem
Ronak Chauhan

10

Der Hauptgrund, warum Entwickler davon dringend abgeraten werden, den Objekt-Manager direkt zu verwenden, besteht darin, dass die Erweiterung bei direkter Verwendung des Objekt-Managers im kompilierten Release-Modus nicht installiert werden kann.

Im Release-Modus wird dies für Ihre Kunden unterbrochen, einschließlich aller Kunden in der Magento Cloud.

Ein relativ großer Teil der Entwickler (ca. 75%) testet ihre Erweiterungen nicht, um festzustellen, ob sie im Release-Modus installiert werden können. Treffen Sie daher nicht auf die Probleme, die durch die falsche Verwendung von ObjectManager entstehen.

Ab 2017 führt der Magento Marketplace einen Kompilierungs- und Installationstest für alle über ihn verkauften Erweiterungen durch. Wenn Ihre Erweiterung den Objekt-Manager direkt verwendet, werden diese Tests nicht bestanden und vom Marktplatz zurückgewiesen, bis Sie das Problem beheben und erneut hochladen.


2

Sie können versuchen, ein Objekt von objectManager zu erstellen, und sollten objectManager nicht direkt verwenden .

Verwenden Sie so etwas wie,

class Example extends \Magento\Framework\View\Element\Template
{
    private $_objectManager;

    public function __construct(
        \Magento\Framework\ObjectManagerInterface $objectmanager
    ){
        $this->_objectManager = $objectmanager;
    }

    public function getExample()
    {
        $customerSession = $this->_objectManager->create("Magento\Customer\Model\Session");
        if ($customerSession->isLoggedIn()) {
            $customerData = $customerSession->getCustomer()->getData();
            /*Your logic*/
        }
    }
}

2
Wenn der Objektmanager ein Singleton ist, warum würde dies einen Unterschied machen?
Domdambrogia
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.