마 젠토 2 : ObjectManager를 직접 사용하거나 사용하지 않습니까?


134

자, 어제 우리는 클래스 / 서식 파일직접적인 사용에ObjectManager 관해 마 젠토 커뮤니티의 다른 사람들과 큰 대화를 나 had습니다 .

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

고통 스럽지만 권장되는 프로세스거치는 대신 :

  • 모듈 만들기
  • 환경 설정 선언
  • 의존성 주입
  • 공개 방법을 선언하다

그러나 여기에 딜레마가 발생합니다. Magento 2 코어 파일은 종종 ObjectManager를 직접 호출합니다 . https://github.com/magento/magento2/blob/develop/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php#L57 에서 간단한 예를 찾을 수 있습니다.

내 질문은 다음과 같습니다.

  • 마 젠토가 왜 우리에게하지 말라고 추천 한 일을 하는가? 그것은 우리가 ObjectManager직접 사용해야하는 경우가 있다는 것을 의미합니까 ? 그렇다면 어떤 경우입니까?
  • ObjectManager를 직접 사용하면 어떤 결과가 발생 합니까?

4
이것을 확인하십시오 : magento.stackexchange.com/q/28617/146
Marius

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 ()를 인식하지 못하므로 생성자 주입으로 대체하지 않았습니다.
Anton Kril


3
@TejabhagavanKollepara 두 질문 모두 읽었습니까? 비슷하지만 훨씬 서로되는 중복에서있다
디지털 Pianism에서 라파엘

답변:


98

ObjectManager를 직접 사용해서는 안됩니다!

규칙의 예외는 다음과 같습니다.

  • 같은 정적 마술 방법에서 __wakeup, serialize
  • 생성자의 역 호환성을 만들어야하는 경우
  • 통합 테스트의 비품과 같은 글로벌 범위에서.
  • 팩토리, 프록시 등과 같은 객체 생성에만 필요한 클래스

2
나는 그것을 직접 사용해서는 안된다는 것을 알고 있지만 왜 마 젠토가 그것을하고 있습니까? ^^
Digital Pianism의 Raphael

2
귀하의 예에서 이전 버전과의 호환성을위한 것입니다
KAndy

이것들은 항상 @deprecated로 표시됩니까?
디지털 Pianism에서 라파엘


5
오 예 친구 나는 단지 혼란스러워 알고 있습니다. 어쩌면 그들은 "그렇게하지만 우리는 아마 여기 저기 몇 가지 실수를 떠난 것을 인식하지 않는다"고 말했다 있어야합니다)
라파엘 디지털 Pianism에서

53

그렇다면 왜 M2가 권장하지 않을 때 왜 객체 관리자에 직접 액세스합니까?

잔인한 대답 : M2는 M1의 포트이며 완전한 재 작성이 아닙니다. 따라서 모든 M2 코드가 아직 완벽하게 이식되었다고 가정하지 마십시오. M2 코드베이스에서 무언가를 찾았다 고해서 "가장 좋은 방법"을 의미하는 것은 아닙니다. 때때로 그것은 단지 "우리는 아직 그것을 고칠 수 없었습니다".

덜 잔인 함 : 다른 반응에 따라 대안이 없으므로 때때로 사용해야합니다. 다른 경우에는 하위 호환성 문제 일 수 있습니다. 또한 프레임 워크 코드는 프레임 워크 코드이기 때문에 직접 사용하는 것이 좋습니다. 그러나 코드를 보지 않고 추측 해야하는 경우 많은 사람들이 실제로 수정되어야하지만 아직 그렇게 우선 순위가 높지 않았습니다.

좋은 육아 조언을 기억하십시오. "아이, 내가하는 말이 아니라 내가하는 말을하십시오!"


9
우수한 따옴표 : 아이, 내가하는 말이 아니라 내가하는 말을하십시오!
sivakumar 2016 년

그것이 작동 방식이 아닙니다
Ansyori

객체 관리자없이 소프트 종속성 문제가있는 Magento 2 권장 방법이 있습니까? 다른 모듈에 소프트 종속성이있는 모듈이 있습니다 (모듈이 존재하면 다른 클래스를로드합니다). DI가 실패 할 것이기 때문에 그 클래스를 DI 할 수 없습니다. 공장이 DI에 실패하기 때문에 해당 클래스의 Factory를 DI로 만들 수도 없습니다.
Nathan Merrill

50

를 사용해서는 안됩니다 \Magento\Framework\App\ObjectManager::getInstance().
의존성 주입의 목적을 무시합니다. 우리는 다시 돌아 왔습니다 Mage::getModel().
개체 관리자는 팩토리에서만 사용 된 다음 생성자에 주입 된 상태로 사용해야합니다.

이것을 사용하는 이점은 작성하는 코드가 적다는 것입니다. 그러나 이것은 OK가 아닙니다.
이것이 여전히 핵심에서 사용된다는 사실은 아직 리팩터링되지 않았기 때문입니다. 그럴 수 있기를 바랍니다.


5
그래서 우리는 마 젠토 코드가 잘못하고 있다는 것에 동의합니다.
디지털 Pianism에서 라파엘

11
권리. 그들은 틀렸다 :).
Marius

나는 그들이 잘못 사용하고 있다고 생각하지 않습니다. 동적 해결이 필요한 경우 (특히 플러그인) 및 BC가 즉시 사용되지 않는 메소드를 유지하는 경우 필요할 때 사용합니다.
nevvermind

2
@nevvermind 팩토리 사용. 당신은 사용 di.xml의 핵심 => 클래스 이름 맵을 작성하고 공장의 생성자에 그지도를 삽입하고 objectmanager을 통해 클래스의 인스턴스를 공장을 사용
마리우스

2
@nevvermind 그러나 Magento 직원의 의견은 귀하의 의견보다 높습니다. 당신은 대담한 편지에서 언급 캔디에서 위의 대답은 "당신이 직접 개체 관리자를 사용하지 말아야"이 : magento.stackexchange.com/a/117103/146 내가 가지 문제에 안개를 지 웁니다 추측.
Marius

22

마 젠토가 왜 우리에게하지 말라고 추천 한 일을 하는가? ObjectManager를 직접 사용해야하는 경우가 있습니까? 그렇다면 어떤 경우입니까?

전체 이야기를 알지 못하면 여기 내 추측이 있습니다.

M2의 개발 과정에서 몇 가지 단계에서 젠토 팀의 발생 교체 자동화 된 스크립트 실행 Mage:getModel(), Mage::getSingleton(), $layout->createBlock()ObjectManager를 사용하는 등.

나중에 리팩토링은 대신 적절한 의존성 주입을 사용하도록 수정했지만 모든 발생을 변환하는 데 시간 / 자원이 충분하지 않았습니다.

또한 Magento 팀은 최근에 이것을 이스케이프 메커니즘으로 사용하는 것 같습니다. 생성자를 변경해야하는 기존 구현을 중단하는 대신 ObjectManager를 통해 새 종속성을 숨기면됩니다. BC주의 휴식을 피하기 위해 더 나쁜 코드를 작성하는이 접근법에 동의한다고 말할 수는 없습니다.

ObjectManager를 직접 사용하면 직접적인 결과는 무엇입니까?

귀하의 질문에 이미 충분한 이유가 있다고 생각합니다. 일반적으로 숨겨진 종속성을 만듭니다. 즉, 종속성은 구현 세부 정보에 있으며 생성자에서만 볼 수 없습니다.


BC는 전혀 문제가되지 않았을 것입니다
Robbie Averill

12

객체 관리자를 직접 사용해서는 안됩니다!

예를 들어 :

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

또한 이벤트 옵저버 또는 플러그인으로 작업하는 경우 직접 사용해서는 안됩니다.

팩토리에서 사용할 수 있지만 먼저 생성자에 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를 사용할 수 없기 때문에 이런 식으로 사용해야합니다!
Ronak Chauhan

이벤트 (관심 자라고 생각합니다) 및 플러그인에서도 사용해서는 안됩니다. ObjectManager가 아닌 필요한 객체를 주입해야합니다. Factory에서만 ObjectManager를 사용할 수 있으며 실제로 전화하는 대신에 주사해야합니다.::getInstance()
7ochem

맞아요, @ 7ochem
Chauhan

더 나은 지식이 있다면 자신의 답변을 추가하거나 다른 사람의 답변을 편집하여 더 나은 아이디어를 얻고 다른 사람에게 도움을 줄 수 있습니다. @ 7ochem
Chauhan

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
객체 관리자가 싱글 톤 인 경우 왜 차이가 발생합니까?
domdambrogia
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.