Magento 2:ObjectManagerを直接使用するかどうか。


134

それでは、昨日、Magentoコミュニティの他の人たちとinクラス/テンプレートの直接的な使用ObjectManagerに関して大きな話をしました。

Alan Kentを引用して、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);

痛みを伴うが推奨されるプロセス経る代わりに

  • モジュールを作成する
  • 設定の宣言
  • 依存関係を注入する
  • パブリックメソッドを宣言する

ただし、ジレンマが発生します。Magento2コアファイルは、多くの場合ObjectManagerを直接呼び出します。ここに簡単な例があります:https : //github.com/magento/magento2/blob/develop/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php#L57

だからここに私の質問があります:

  • なぜMagentoは私たちにしないことを勧めているのですか?それはObjectManager直接使用する必要がある場合があることを意味ますか?もしそうなら、それらのケースは何ですか?
  • ObjectManagerを直接使用し結果はどうなりますか?

4
これを確認してください:magento.stackexchange.com/q/28617/146
マリウス

3
関連リンク:mwop.net/blog/2016-04-26-on-locators.html。それの関連ビットはそうでしょう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にも当てはまります。There are valid use casesセクションも確認してください。これもここに適用されます。
-nevvermind

3
OMがすでに存在していたM2開発の期間がありましたが、コンストラクター注入を使用するようにmagento全体はまだ変更されていません。その時点で、多くの人がMage :: getSingleton()をObjectManager :: getInstance()-> get()に置き換えました。そのような使用法のほとんどは、その期間に導入されました。後ですべてのMage :: getSingleton()呼び出しは、ツールによるコンストラクター挿入に置き換えられましたが、ツールはObjectManager :: getInstance()を認識しなかったため、コンストラクター挿入に置き換えられませんでした。
アントンクリル


3
@TejabhagavanKolleparaは両方の質問を読みましたか?似ていますが、互いに重複しているわけではありません
デジタルピアニズムのラファエル

回答:


98

ObjectManagerを直接使用しないでください!

ルールの例外は次のとおりです。

  • 以下のような静的な魔法のメソッドでは __wakeupserializeなど、
  • コンストラクタの後方互換性を確保する必要がある場合
  • 統合テストの備品のように、グローバルな範囲で。
  • ファクトリ、プロキシなどのオブジェクトの作成にのみ必要なクラス内

2
直接使用しないでくださいが、Magentoが使用しているのはなぜですか?^^
デジタルピアニズムのラファエル

2
あなたの例では下位互換性のためです
-KAndy

それらは常に@deprecatedとしてフラグが付けられていますか?
デジタルピアニズムのラファエル


5
ええ、私はそれがただ紛らわしいことを知っています。たぶん、彼らは「それを行うが、我々は、おそらくここにあるいくつかのミスを残していることに注意していない」と述べているはずです。)
ラファエルデジタルPianismで

53

それでは、M2が推奨しないのに、なぜオブジェクトマネージャに直接アクセスするのですか?

残忍な答え:M2はM1の移植版であり、完全な書き換えではありません。(残念ながら)すべてのM2コードがまだ完全に移植されていると想定しないでください。M2コードベースで何かを見つけたからといって、それが「その最適な方法」を意味するわけではありません。時々、「まだ修正できていない」だけです。

それほど残忍ではありません:他の回答によると、代替手段がないため、時々使用する必要があります。また、後方互換性の理由による場合もあります。また、フレームワークコードはフレームワークコードであるため、直接使用するのが理にかなっています。しかし、コードを見ずに推測しなければならない場合、多くは実際に修正する必要がありますが、それを行うにはまだ十分な優先順位がありません。

良い子育てのアドバイスを覚えておいてください:「子供たち、私が言うことではなく、私が言うことをしてください!


9
優秀な引用:子供たち、私が言うことをしてください、私がすることではありません!
sivakumar

それはそれがどのように機能するかではありませんkiddo
Ansyori

オブジェクトマネージャなしでソフト依存関係の問題を抱えるMagento 2推奨の方法はありますか?別のモジュールにソフト依存関係を持つモジュールがあります(モジュールが存在する場合、別のクラスをロードします)。DIが失敗するので、そのクラスをDIにすることはできません。ファクトリはDIに失敗するため、そのクラスのファクトリをDIすることさえできません。
ネイサンメリル

50

使用しないでください\Magento\Framework\App\ObjectManager::getInstance()
依存性注入の目的を無効にします。に戻りましたMage::getModel()
オブジェクトマネージャーは、工場でのみ使用し、コンストラクターに注入する必要があります。

これを使用する利点は、記述するコードが少ないことです。しかし、これではうまくいきません。
これがまだコアで使用されているという事実は、まだリファクタリングされていないためです。そうなることを願っています。


5
だから、Magentoのコードは間違っているのではないでしょうか?
デジタルピアニズムのラファエル

11
右。彼らは間違ってる :)。
マリウス

私は彼らが間違っているとは思わない。彼らは必要なときにそれを使用しています:動的な解決が必要なとき(特にプラグイン)、そしてすぐに廃止されたメソッドでBCを維持するとき。
nevvermind

2
@nevvermindファクトリーを使用します。あなたは使うdi.xmlキー=>クラス名のマップを作成し、工場のコンストラクタにして、そのマップを注入してのObjectManagerを通じてクラスをインスタンス化するファクトリを使用する
マリウス

2
@nevvermindしかし、Magentoの従業員の意見はあなたの意見を上回っています。上記のKAndyからの答えがあります。太字で「オブジェクトマネージャーを直接使用しないでください」と書かれています。magento.stackexchange.com / a / 117103 / 146この種の問題が霧をクリアすると思います。
マリウス

22

なぜMagentoは私たちにしないことを勧めているのですか?つまり、ObjectManagerを直接使用する必要がある場合がありますか?もしそうなら、それらのケースは何ですか?

ここで完全なストーリーを知らずに私の推測です:

M2の開発中に、いくつかの段階でMagentoのチームはの出現置き換え自動スクリプト実行Mage:getModel()Mage::getSingleton()$layout->createBlock()のObjectManagerを使用する、など。

後のリファクタリングでは、これを修正して適切な依存性注入を代わりに使用する必要がありましたが、すべての出現を変換するのに十分な時間/リソースがありませんでした。

また、Magentoチームは最近、これをエスケープメカニズムとして使用しているようです。既存の実装を壊す代わりに(コンストラクターを変更する必要がある)、ObjectManagerを介して新しい依存関係を単純に非表示にします。私はこのアプローチに同意するとは言えません-BCの中断を避けるために、より悪いコードを書く。

ObjectManagerを直接使用することの直接的な影響は何ですか?

あなたの質問にはすでに十分な理由が含まれていると思います。通常、非表示の依存関係が作成されます。言い換えると、依存関係は実装の詳細にあり、コンストラクターだけからは見えません。


適切BCはまったく問題がなかったであろう公衆にリリースする前に、それをそこに行っていたので、それは皮肉である
ロビーエーヴリル

12

オブジェクトマネージャを直接使用しないでください!

例えば:

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

また、イベントオブザーバーまたはプラグインを使用している場合は、直接使用しないでください。

Factoriesで使用できますが、最初にConstructorでObject Managerを注入する必要があることを除いて、メソッドでそのオブジェクトを使用できます。

使用することを推奨:

1)プライベートオブジェクトを宣言します。

private $_objectManager;

2)コンストラクターに注入して初期化する:

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

3)何らかの方法で使用する:

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

この回答は、Magento 2.2バージョン以下のものですので、注意してください。新しいMagento 2標準に従って、objectManagerインスタンスも使用できなくなりました。データを取得するには、オブジェクトクラスまたはリポジトリのファクトリを使用する必要があります。


このように使用するのは良い習慣ですか?
enrico69

はい、magentoでは直接objectManagerを使用できないため、この方法を使用する必要があります。
ロナックチャウハン

また、イベント(オブザーバーを意味すると思います)やプラグインで使用しないでください。ObjectManagerではなく、必要なオブジェクトを注入する必要があります。ファクトリーでのみObjectManagerを使用できます。次に、呼び出すのではなく、実際に注入する必要があります::getInstance()
7ochem

右、答えを編集してください@ 7ochem
ロナックチャウハン

答えを下げることは適切な方法ではありません。より良い知識がある場合は、独自の答えを追加するか、他の答えを編集して、より良いアイデアを得て他の人に役立ちます。@ 7ochem
ロナックチャウハン

10

開発者がObject Managerを直接使用することを強くお勧めしない主な理由は、Object Managerを直接使用すると、拡張機能がコンパイル済みリリースモードでインストールできないことです。

そのため、Magento Cloudのすべての顧客を含む、リリースモードを使用している顧客にとっては中断されます

開発者のかなりの割合(約75%)がリリースモードでインストールできるかどうかを確認するために拡張機能をテストしないため、ObjectManagerの不適切な使用によって引き起こされる問題に遭遇しないようです。

2017年現在、Magento Marketplaceは、販売されているすべての拡張機能に対してコンパイルとインストールのテストを実行します。拡張機能がオブジェクトマネージャを直接使用している場合、これらのテストに失敗し、この問題を解決して再アップロードするまでマーケットプレイスから拒否されます。


2

objectManagerのオブジェクトを作成して試すことができます。objectManagerを直接使用しないください

次のようなものを使用します

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
オブジェクトマネージャーがシングルトンの場合、なぜこれが違いを生むのでしょうか?
dombrobrogia
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.