Magento 2: doğrudan ObjectManager'ı kullanmak veya kullanmamak?


134

Tamam, dün, Magento topluluğunun diğer insanlarıyla sınıfların / şablonların doğrudan kullanımıObjectManager konusunda büyük bir konuşma yaptık .

Alan Kent'ten alıntı yaparak ObjectManager'ı doğrudan kullanmamamızın nedenlerinin farkındayım :

Birkaç sebep var. Kod işe yarar, ancak ObjectManager sınıfına doğrudan başvurmamak en iyisidir.

  • Çünkü biz öyle diyoruz! ;-) (daha iyi tutarlı kod olarak ifade edilir iyi koddur)
  • Kod gelecekte farklı bir bağımlılık enjeksiyon çerçevesiyle kullanılabilir
  • Test etmek daha kolaydır - sahte bir ObjectManager vermek zorunda kalmadan, istenen sınıf için sahte argümanlara geçersiniz
  • Bağımlılıkları daha net tutar - kodun ortasında saklı bağımlılıklardan ziyade, kodun yapıcı listesi üzerinden neye bağlı olduğu açıktır.
  • Programcıları kapsülleme ve modülerleştirme gibi kavramlar hakkında daha iyi düşünmeye teşvik eder - eğer yapıcı büyürse, kodun yeniden yapılandırılması gereken bir işaret olabilir.

StackExchange'te gördüklerime göre, birçok insan örneğin kolay / kısa / tavsiye edilmeyen bir çözüm bulma eğilimindedir :

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

Acı verici ama önerilen bir işlemden geçmek yerine :

  • modül oluşturma
  • tercihleri ​​bildirme
  • bağımlılıkları enjekte etmek
  • genel bir yöntem belirtmek

Ancak ve işte ikilem geliyor, Magento 2 çekirdek dosyaları genellikle doğrudan ObjectManager'ı çağırır . Hızlı bir örnek burada bulunabilir: https://github.com/magento/magento2/blob/develop/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php#L57

Sorularım işte burada:

  • Magento neden yapmamamızı önerdiği şeyi yapıyor? Bu ObjectManagerdoğrudan kullanmamız gereken bazı durumlar olduğu anlamına mı geliyor ? Eğer öyleyse, bu davalar nelerdir?
  • ObjectManager'ı doğrudan kullanmanın sonuçları nelerdir ?


3
İlgili link: mwop.net/blog/2016-04-26-on-locators.html . Bunun ilgili kısmı olurdu The intent of zend-servicemanager is for use as an Inversion of Control container. It was never intended as a general purpose service locator [...]. M2 için de geçerli. Ayrıca There are valid use casesburada da geçerli olan kısmı kontrol edin .
nevvermind

3
OM zaten oradayken bir miktar M2 gelişme dönemi vardı, ancak magento, yapıcı enjeksiyonunu kullanmak için henüz değişmedi. Bu noktada birçok kişi Mage :: getSingleton () 'ı ObjectManager :: getInstance () -> get () ile değiştirdi. Bu tür kullanımların çoğu o dönemde tanıtıldı. Daha sonra tüm Mage :: getSingleton () çağrıları bir araç tarafından yapıcı enjeksiyonu ile değiştirildi, ancak araç ObjectManager :: getInstance () öğesini tanımadı, bu yüzden yapıcı enjeksiyonu ile değiştirmedi.
Anton Kril


3
@TejabhagavanKollepara iki soruyu da okudunuz mu? Benzer ama birbirlerinden
kopuk

Yanıtlar:


98

ObjectManager'ı doğrudan kullanmamalısınız!

Kuralın istisnası:

  • gibi statik sihirli yöntemlerde __wakeup, serializevb
  • Yapıcıya geriye dönük uyumluluk yapmanız durumunda
  • Küresel kapsamda, entegrasyon testi fikstürlerinde olduğu gibi.
  • Sadece fabrika, proxy, vs. gibi nesnelerin yaratılması için ihtiyaç duyulan sınıfta

2
Asla doğrudan kullanmamam gerektiğini biliyorum ama Magento neden yapıyor? ^^
Raphael, Digital Pianism'de


Bunlar her zaman @deprecated olarak işaretlenir mi?
Raphael, Digital Pianism'de


5
oh evet dostum biliyorum ki kafam karıştı. Belki onlar "bunu ama biz muhtemelen orada burada bazı hatalar bırakmış farkında değil" dedi olmalı;)
Raphael Dijital pianism en

53

Öyleyse M2 neden biz buna karşı önerdiğimizde doğrudan nesne yöneticisine doğrudan erişiyor?

Acımasız cevap: M2, M1'in limanıdır - tam bir yeniden yazma değil. Bu nedenle, tüm M2 kodlarının henüz mükemmel şekilde taşındığını varsaymayın (ne yazık ki). M2 kod tabanında bir şey bulduğunuz için, bu "yapmanın en iyi yolu" anlamına gelmez. Bazen sadece "henüz tamir etmek için buralarda olmadık".

Daha az acımasız: Diğer yanıtlara göre, bazen alternatif olmadığından kullanmalısınız. Diğer zamanlarda geriye dönük uyumluluk nedenleriyle olabilir. Ve çerçeve kodu bazen doğrudan kullanmak mantıklıdır, çünkü çerçeve kodudur. Ancak, koda bakmadan tahmin etmek zorunda kalsaydım, çoğu gerçekten düzeltilmeli, ancak henüz bunu yapmak için yeterince öncelikli olmamıştı.

Sadece iyi ebeveynlik tavsiyelerini hatırlayın: "Çocuklar, söylediklerimi yapın, yaptığımı değil!"


9
Mükemmel alıntı: Çocuklar, söylediklerimi yapın, yaptığım şeyi değil!
sivakumar

Bu
kiddo

Nesne yöneticisi olmadan yumuşak bir bağımlılık sorunu yaşamanın Magento 2 tarafından önerilmiş bir yolu var mı? Başka birine yumuşak bağımlılığı olan bir modül var (modül varsa, başka bir sınıfı yükler). Bu sınıfa DI giremem çünkü DI başarısız olur. Bu sınıf için bir Fabrika DI bile yapamıyorum çünkü fabrika DI'ye başarısız olacak.
Nathan Merrill,

50

Asla kullanmamalısın \Magento\Framework\App\ObjectManager::getInstance().
Bağımlılık enjeksiyonunun amacını yendi. Geri döndük Mage::getModel().
Nesne yöneticisi yalnızca fabrikalarda kullanılmalı ve daha sonra bir kurucuya enjekte edilmeli.

Bunu kullanmanın avantajı yazmak için daha az koddur. Ancak bu doğru yapmaz.
Bunun hala çekirdekte kullanıldığı gerçeği, henüz refaktör olmadığından kaynaklanmaktadır. Umarım olacak.


5
Yani ikimiz de Magento kodunun yanlış yaptığına katılıyoruz.
Raphael, Digital Pianism'de

11
sağ. Onlar yanlış :).
Marius

Yanlış kullandıklarını sanmıyorum. Gerektiğinde kullanıyorlar: dinamik çözümleme gerektiğinde (özellikle eklentilerde) ve BC'yi hemen kullanımdan kaldırılmış yöntemlerle tutarken.
nevvermind

2
@ nevvermind Bir fabrika kullanma. Kullanılacak di.xmlanahtar => sınıf adı haritası oluşturmak için ve fabrikanın yapıcısına bu haritayı enjekte ve ObjectManager yoluyla sınıf örneğini oluşturmak için fabrika kullanmak
Marius

2
@nevvermind Ancak bir Magento çalışanının görüşü, fikrinizi dışlıyor. Yukarıda KAndy'den gelen ve "doğrudan nesne yöneticisini kullanmamalısınız" harfini belirten bir cevabınız var: magento.stackexchange.com/a/117103/146 Sanırım bu konudaki sisi temizliyor.
Marius

22

Magento neden yapmamamızı önerdiği şeyi yapıyor? Bu, ObjectManager'ı doğrudan kullanmamız gereken bazı durumlar olduğu anlamına mı geliyor? Eğer öyleyse, bu davalar ne?

Buradaki tüm hikayeyi bilmeden benim tahminim:

M2 gelişimi sırasında bazı aşamada Magento ekibi tekrarlarını yerini otomatik bir komut dosyası koştu Mage:getModel(), Mage::getSingleton(), $layout->createBlock()ObjectManager kullanmak, vb.

Daha sonra yeniden düzenleme, bunun yerine uygun bağımlılık enjeksiyonunu kullanmak için bunu düzeltmiş olmalıydı, ancak tüm oluşumları dönüştürmek için yeterli zaman / kaynak yoktu.

Ayrıca Magento ekibi son zamanlarda bunu bir kaçış mekanizması olarak kullanıyor gibi görünüyor. Mevcut bir uygulamayı bozmak yerine (yapıcıyı değiştirmek zorunda kalarak) yeni bağımlılığı ObjectManager aracılığıyla gizlerler. Bu yaklaşıma katılıyorum diyemem - BC'nin bozulmaması için daha kötü kod yazıyor.

ObjectManager'ı doğrudan kullanmanın doğrudan sonuçları nelerdir?

Bence sorunuz zaten yeterli nedenler içeriyor. Genel olarak gizli bir bağımlılık yaratır, başka bir deyişle bağımlılık uygulama detaylarındadır ve yalnızca kurucudan görülemez.


Düzgün M.Ö. hiç bir sorun olmazdı halka bırakmadan önce orada yapmıştı çünkü ironik
Robbie Averill

12

Nesne yöneticisini doğrudan kullanmamalısınız!

Örneğin:

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

Ayrıca, etkinlik gözlemcileri veya eklentileri ile çalışıyorsanız, asla doğrudan kullanmamalısınız.

Fabrikalarda kullanabilirsiniz, ancak önce Nesne Yöneticisini Kurucuya enjekte etmeniz ve ardından nesnesini yönteminizde kullanabilirsiniz.

Kullanmak için tercih edilir:

1) özel nesne bildir:

private $_objectManager;

2) yapıcıya enjekte edilir ve başlatılır:

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

3) bazı yöntemlerde kullanın:

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

Bu cevap Magento 2.2 sürümleri için geçerlidir, lütfen not alınız. Yeni Magento 2 standartlarına göre, artık objectManager örneğini bile kullanamıyoruz. Herhangi bir veri almak için nesne sınıfının veya havuzun fabrikasını kullanmalıyız.


Bu şekilde kullanmak iyi bir pratik mi?
enrico69

Evet, çünkü magento, doğrudan objectManager'ı kullanmaya izin vermediğinden, bu şekilde kullanmanız gerekir!
Ronak Chauhan

Ayrıca olaylarda (gözlemciyi kastediyorsunuz sanırım) ve eklentilerde asla kullanmamalısınız. ObjectManager'a değil, ihtiyacınız olan nesneleri enjekte etmeniz gerekir. Sadece bir Fabrikada ObjectManager'ı kullanabilir ve daha sonra aramak yerine gerçekten enjekte etmelisiniz::getInstance()
7ochem

Doğru, cevap @ 7ochem
Ronak Chauhan

Herhangi bir cevabı reddetmek uygun bir yöntem değildir, daha iyi bilgiye sahipseniz, kendi cevabınızı ekleyebilir veya başkalarına daha iyi bir fikir ve yardım almak için başkalarının cevabını düzenleyebilirsiniz. @ 7ochem
Ronak Chauhan

10

Geliştiricilerin doğrudan Nesne Yöneticisi'ni kullanmaktan kesinlikle vazgeçilmelerinin ana nedeni, Nesne Yöneticisi'nin doğrudan kullanımının, uzantının derlenmiş sürüm modunda yüklenememesine neden olmasıdır.

Bu nedenle , Magento Bulutu'ndaki tüm müşteriler de dahil olmak üzere, serbest bırakma modunu kullanarak müşterileriniz için ayrılıyor .

Oldukça büyük oranda geliştiricilerin oranı (yaklaşık% 75), sürümlerinde yüklenip yüklenemeyeceklerini görmek için uzantılarını test etmiyor gibi görünüyor, bu nedenle hatalı ObjectManager kullanımı tarafından ortaya konan sorunlara rastlamayın.

2017 itibariyle, Magento Marketi, üzerinden satılan tüm eklentiler üzerinde bir derleme ve kurulum testi gerçekleştiriyor. Uzantınız doğrudan Nesne Yöneticisini kullanıyorsa, bu testleri geçemez ve siz bu sorunu çözüp yeniden yükleyene kadar Market'ten reddedilir.


2

Bir objectManager nesnesi oluşturarak deneyebilirsiniz ve doğrudan objectManager kullanmamalısınız .

Gibi bir şey kullanın

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
Nesne yöneticisi bir singleton ise, bu neden bir fark yaratır?
domdambrogia
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.