PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

DI w Magento 2 – kontener, Virtual Types, Factory, shared/non-shared

by Henryk Tews / wtorek, 09 lipca 2019 / Opublikowano w Magento 2

Dependency Injection w Magento 2 to temat, który na początku wygląda jak magia. Wpisujesz interfejs w konstruktorze, a Magento samo dostarcza właściwą implementację. Skąd wie co wstrzyknąć? Jak działa kompilacja DI? Co to są virtual types i po co są? Rozkładam to na czynniki pierwsze.

Podstawy – czym jest kontener DI

Kontener DI to mechanizm, który buduje obiekty za Ciebie – razem z ich zależnościami. Zamiast pisać:

<?php

// Bez DI – ręczne tworzenie zależności
$logger     = new \Monolog\Logger('app');
$repository = new ProductRepository($logger, new DbConnection());
$service    = new ProductService($repository, $logger);

Prosisz kontener o obiekt, a on sam rozwiązuje całe drzewo zależności:

<?php

// Z DI – kontener buduje całe drzewo
$service = $objectManager->get(ProductService::class);

W Magento 2 nigdy nie używasz ObjectManager bezpośrednio w swoim kodzie (poza Factory i Proxy). Zależności deklarujesz w konstruktorze, a Magento wstrzykuje je automatycznie.

Jak Magento rozwiązuje typy – di.xml i kompilacja

Gdy Magento widzi w konstruktorze interfejs, szuka w plikach di.xml zarejestrowanego preference:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <!-- Gdy ktoś poprosi o ProductRepositoryInterface, daj mu ProductRepository -->
    <preference for="Magento\Catalog\Api\ProductRepositoryInterface"
                type="Magento\Catalog\Model\ProductRepository"/>

</config>

Podczas kompilacji (bin/magento setup:di:compile) Magento analizuje wszystkie di.xml ze wszystkich modułów, buduje kompletny graf zależności i generuje klasy Interceptor (dla pluginów) oraz Proxy. Wynik trafia do generated/. Dlatego po zmianie di.xml trzeba uruchomić kompilację – w trybie developer Magento robi to automatycznie.

Argumenty konstruktora – wstrzykiwanie konkretnych wartości

Przez di.xml możesz nie tylko mapować interfejsy na klasy, ale też przekazywać konkretne wartości do konstruktorów:

<?xml version="1.0"?>
<config>
    <type name="Vendor\Module\Model\ApiClient">
        <arguments>
            <argument name="timeout" xsi:type="number">30</argument>
            <argument name="baseUrl" xsi:type="string">https://api.example.com</argument>
            <argument name="logger" xsi:type="object">Psr\Log\LoggerInterface</argument>
        </arguments>
    </type>
</config>
<?php

namespace Vendor\Module\Model;

class ApiClient
{
    public function __construct(
        private \Psr\Log\LoggerInterface $logger,
        private string $baseUrl,
        private int $timeout = 10
    ) {}
}

Virtual Types – klasy bez pisania kodu PHP

Virtual Type to jeden z najbardziej niedocenianych mechanizmów Magento 2. Pozwala stworzyć „nową klasę” przez konfigurację XML – bez pisania ani jednej linii PHP. Przydatne gdy chcesz mieć dwie instancje tej samej klasy z różnymi parametrami:

<?xml version="1.0"?>
<config>
    <!-- Tworzymy "wirtualną klasę" FileLogger opartą na Monolog\Logger -->
    <virtualType name="Vendor\Module\Model\FileLogger"
                 type="Magento\Framework\Logger\Monolog">
        <arguments>
            <argument name="name" xsi:type="string">file_logger</argument>
        </arguments>
    </virtualType>

    <!-- I drugą z inną konfiguracją -->
    <virtualType name="Vendor\Module\Model\ApiLogger"
                 type="Magento\Framework\Logger\Monolog">
        <arguments>
            <argument name="name" xsi:type="string">api_logger</argument>
        </arguments>
    </virtualType>

    <!-- Wstrzyknięcie konkretnego loggera do konkretnej klasy -->
    <type name="Vendor\Module\Model\ApiClient">
        <arguments>
            <argument name="logger" xsi:type="object">Vendor\Module\Model\ApiLogger</argument>
        </arguments>
    </type>
</config>

Virtual Types istnieją tylko w kontenerze DI – nie możesz ich użyć jako type hinta w PHP. Ale możesz je wstrzykiwać jako argumenty przez xsi:type="object".

Shared vs Non-shared – singleton czy nowy obiekt?

Domyślnie Magento tworzy każdą klasę jako singleton w obrębie jednego requestu – kontener zwraca tę samą instancję przy kolejnych wywołaniach. Możesz to zmienić:

<?xml version="1.0"?>
<config>
    <!-- shared="false" = nowa instancja przy każdym wstrzyknięciu -->
    <type name="Vendor\Module\Model\Cart">
        <arguments>
            <argument name="shared" xsi:type="boolean">false</argument>
        </arguments>
    </type>
</config>

W praktyce gdy potrzebujesz wielu instancji tej samej klasy (np. przy przetwarzaniu wielu zamówień w pętli), Magento generuje dla Ciebie klasę Factory:

<?php

// Magento generuje Vendor\Module\Model\OrderFactory automatycznie
// jeśli poprosisz o nią w konstruktorze

class OrderProcessor
{
    public function __construct(
        private \Vendor\Module\Model\OrderFactory $orderFactory
    ) {}

    public function processMany(array $orderData): void
    {
        foreach ($orderData as $data) {
            // Każde create() zwraca nową instancję Order
            $order = $this->orderFactory->create(['data' => $data]);
            $order->process();
        }
    }
}

Podsumowanie

Kontener DI w Magento 2 to potężne narzędzie, które przy dobrym zrozumieniu pozwala pisać kod elastyczny i łatwy do testowania. Kluczowe rzeczy do zapamiętania: preference mapuje interfejsy na implementacje, Virtual Types pozwalają konfigurować warianty klas bez PHP, a Factory to rozwiązanie gdy potrzebujesz wielu instancji jednej klasy.

About Henryk Tews

Co możesz przeczytać następne

Cron – grupy, własne joby, harmonogram z panelu admina, debugowanie
OpenSearch 3.x vector search – embeddingi przez Ollama, k-NN, hybrid search
B2B – Company, Shared Catalog, Negotiable Quote, Requisition List, własne pluginy
  • Publikacje
  • O autorze
  • Kontakt

© 2026 Created by

GÓRA
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Zawsze aktywne
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Zarządzaj opcjami
  • Zarządzaj serwisami
  • Zarządzaj {vendor_count} dostawcami
  • Przeczytaj więcej o tych celach
Zobacz preferencje
  • {title}
  • {title}
  • {title}