Mengapa beberapa kelas mendefinisikan injeksi pada konstruktor dan di.xml?

12

Saya tidak mengerti mengapa, di beberapa kelas, injeksi ketergantungan mereka dideklarasikan dua kali - sekali di di.xmldan di konstruktor kelas beton.

Misalnya dalam Magento\Backend\Model\Url, di.xmlini memiliki set tipe untuk DI didefinisikan:

<type name="Magento\Backend\Model\Url">
    <arguments>
        <argument name="scopeResolver" xsi:type="object">
Magento\Backend\Model\Url\ScopeResolver</argument>
        <argument name="authSession" xsi:type="object">
Magento\Backend\Model\Auth\Session\Proxy</argument>
        <argument name="formKey" xsi:type="object">
Magento\Framework\Data\Form\FormKey\Proxy</argument>
        <argument name="scopeType" xsi:type="const">
Magento\Store\Model\ScopeInterface::SCOPE_STORE </argument>
        <argument name="backendHelper" xsi:type="object">
Magento\Backend\Helper\Data\Proxy</argument>
    </arguments>
</type>

Tetapi pada saat yang sama, dalam kelas konkretnya, kelas-kelas yang didefinisikan dalam di.xml yang diperlukan untuk injeksi dinyatakan kembali dalam konstruktor:

<?php
    public function __construct(
        \Magento\Framework\App\Route\ConfigInterface $routeConfig,
        \Magento\Framework\App\RequestInterface $request,
        \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo,
        \Magento\Framework\Url\ScopeResolverInterface $scopeResolver,
        \Magento\Framework\Session\Generic $session,
        \Magento\Framework\Session\SidResolverInterface $sidResolver,
        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory,
        \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        $scopeType,
        \Magento\Backend\Helper\Data $backendHelper,
        \Magento\Backend\Model\Menu\Config $menuConfig,
        \Magento\Framework\App\CacheInterface $cache,
        \Magento\Backend\Model\Auth\Session $authSession,
        \Magento\Framework\Encryption\EncryptorInterface $encryptor,
        \Magento\Store\Model\StoreFactory $storeFactory,
        \Magento\Framework\Data\Form\FormKey $formKey,
        array $data = []
) {
    //...
}
?>

Jika kita melihat konstruktornya di atas,, \Magento\Framework\App\Route\ConfigInterface $routeConfigmisalnya, tidak didefinisikan dalam di.xml. Itu hanya didefinisikan dalam konstruktor dan Magento masih akan menyuntikkan routeConfigke dalam kelas untuk digunakan, bukan? Sama untuk \Magento\Framework\Encryption\EncryptorInterface $encryptordan beberapa lainnya.

Lalu, mengapa ada kebutuhan untuk mendefinisikan injeksi lain di kedua di.xmldan di konstruktor ketika memiliki deklarasi di konstruktor cukup untuk Magento untuk menyuntikkan dependensi ke dalam kelas untuk digunakan?

xenon
sumber

Jawaban:

15

Sebagaimana dinyatakan dalam dokumentasi , di Magento 2, di.xmldapat digunakan untuk melakukan hal berikut:

Anda bisa mengonfigurasi argumen konstruktor kelas di di.xmldalam argumen Anda. Manajer objek menyuntikkan argumen ini ke dalam kelas selama pembuatan. Nama argumen yang dikonfigurasi dalam file XML harus sesuai dengan nama parameter di konstruktor di kelas yang dikonfigurasi.

Dalam kasus Anda, ini sedikit rumit. Saya akan menjelaskan setiap argumen satu per satu:

  • \Magento\Framework\App\Route\ConfigInterface $routeConfig: ini adalah antarmuka sehingga tidak dapat digunakan secara langsung . The preferensi untuk kelas ini didefinisikan dalamapp/etc/di.xml dan merupakan Magento\Framework\App\Route\Configkelas
  • \Magento\Framework\App\RequestInterface $request : sama berlaku untuk kelas ini, preferensi adalah Magento\Framework\App\Request\Http
  • \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo: kasus yang sama di sini lagi dengan Magento\Framework\Url\SecurityInfo\Proxypreferensi
  • \Magento\Framework\Url\ScopeResolverInterface $scopeResolver: di sini kita mulai dengan bit yang menarik. Dalam app/etc/di.xmlpreferensi didefinisikan untuk antarmuka ini dan itu adalah Magento\Framework\Url\ScopeResolverkelas. Namun, untuk Magento\Backend\Model\UrlMagento 2 perlu menggunakan kelas lain dan dengan demikian itu menentukan kelas mana yang di.xmlAnda posting sehingga Magento\Backend\Model\Url\ScopeResolverakan digunakan.
  • \Magento\Framework\Session\Generic $session ini adalah kelas normal dan karenanya dapat digunakan seperti itu.
  • \Magento\Framework\Session\SidResolverInterface $sidResolver: kembali ke antarmuka, preferensi masih didefinisikan app/etc/di.xmldan ituMagento\Framework\Session\SidResolver\Proxy
  • \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory : ini adalah kelas pabrik sehingga dapat digunakan seperti itu.
  • \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver: kembali ke app/etc/di.xmlpreferensi kami dan adalahMagento\Framework\Url\QueryParamsResolver
  • \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig: kasus lain di sini di mana ** preferensi didefinisikan app/etc/di.xmldan itu Magento\Framework\App\Config.
  • $scopeType: di sini kita hanya memiliki variabel tanpa kelas di depannya. Modul Anda di.xmlmenentukan yang Magento\Store\Model\ScopeInterface::SCOPE_STOREharus digunakan sebagai nilai variabel ini. **
  • \Magento\Backend\Helper\Data $backendHelper: di sini kita bisa menggunakan kelas itu seperti itu. Namun di sini proxy digunakan karena kelas ini belum tentu digunakan (lihat posting ini untuk detail tentang kelas proxy: Magento 2: penjelasan praktis tentang apa itu kelas proxy? )
  • \Magento\Backend\Model\Menu\Config $menuConfig : kita bisa menggunakan kelas ini apa adanya.
  • \Magento\Framework\App\CacheInterface $cache: preferensi lain yang ditentukan app/etc/di.xmluntuk antarmuka ini yaituMagento\Framework\App\Cache\Proxy
  • \Magento\Backend\Model\Auth\Session $authSession: sama lagi di sini kita bisa menggunakan kelas seperti itu tetapi kita menggunakan kelas proxy sebagai gantinya untuk memuat malas.
  • \Magento\Framework\Encryption\EncryptorInterface $encryptor: melompat ke app/etc/di.xmllagi dan kami temukan Magento\Framework\Encryption\Encryptorsebagai preferensi
  • \Magento\Store\Model\StoreFactory $storeFactory : sebuah pabrik sehingga kami dapat menggunakannya sebagaimana adanya.
  • \Magento\Framework\Data\Form\FormKey $formKey: di sini kita menggunakan Magento\Framework\Data\Form\FormKey\Proxykelas proxy lagi untuk memuat malas.
  • array $data = []: yang ini selalu menjadi yang terakhir dan secara otomatis default ke array kosong Anda dapat menemukan informasi lebih lanjut di sini: Magento 2: apa parameter konstruktor array data $?

Untuk meringkas

Secara global, parameter konstruktor kelas adalah antarmuka atau kelas yang tidak dapat dipakai. Dengan demikian di.xmlmemungkinkan Anda menyesuaikan dependensi yang ingin Anda gunakan untuk setiap konstruktor kelas. Ini juga berlaku untuk kelas instantiable. Misalnya konstruktor kelas yang mengambil kelas produk sebagai argumen konstruktor. Ini dapat disesuaikan dalam modul produk yang dapat dikonfigurasi sehingga dibutuhkan kelas produk yang dapat dikonfigurasi sebagai argumen.

Raphael di Digital Pianism
sumber
Apakah preferensi selalu diperlukan untuk parameter antarmuka? Bisakah itu dilihat sebagai mundur? Apakah masuk akal untuk mendefinisikan argumen konkret dalam konfigurasi tanpa memiliki preferensi di mana pun? Atau apakah itu tidak mungkin?
robsch
6

Penting untuk memahami perbedaan antara definisi dependensi dan konfigurasi dependensi.

Dependensi tidak didefinisikan di dalam di.xml. Dependensi didefinisikan di dalam konstruktor dari kelas masing-masing dengan menentukan antarmuka, abstrak atau pabrik sebagai jenis ketergantungan itu, misalnya $routeConfigketergantungan jenis \Magento\Framework\App\Route\ConfigInterface.

Di sisi lain, di.xmladalah tempat untuk mengkonfigurasi dependensi dengan menggunakan <preference/>node dan / atau xpath:type/arguments/argumentnode (kadang-kadang ditambah dengan node konfigurasi yang lebih maju seperti <virtualType/>atau <proxy/>). Mengkonfigurasi ketergantungan berarti memetakan argumen konstruktor objek ke implementasi / objek / konkret .

Anda ingin agar dependensi dapat dikonfigurasi melalui di.xml sehingga Anda dapat menukar mereka dan menggunakan implementasi yang berbeda untuk antarmuka atau argumen tertentu dalam kondisi tertentu (baca contoh untuk memahami apa yang dimaksud dengan kondisi tertentu).

Misalnya, saat mengembangkan ekstensi Anda, Anda harus membuat kelas baru (kami menyebut kelas baru ini sebagai implementasi ). Kelas baru Anda mengimplementasikan \Magento\Framework\App\Route\ConfigInterfaceantarmuka dan di dalamnya memiliki fungsi konkret yang menghormati kontrak antarmuka. Sekarang mulai bagian konfigurasi : untuk memberi tahu Magento agar menggunakan implementasi yang baru Anda tentukan, Anda harus mengonfigurasi implementasi ini sebagai ketergantungan untuk objek Magento\Backend\Model\Url . Anda melakukan konfigurasi ini di dalam di.xmlfile atau modul Anda. Dalam hal ini Anda perlu menggunakan <preference/>node untuk memetakan antarmuka untuk implementasi baru Anda. Lain kali Anda akan menggunakan xpath:type/arguments/argument di.xmlnode yang lebih granularhanya memetakan argumen tertentu (alias dependensi, alias antarmuka) yang konkret untuk implementasi tertentu . Sekarang, implementasi Anda hanya akan aktif sebagai dependensi untuk objek \Magento\Backend\Model\Url dalam kondisi tertentu , misalnya, dalam aliran eksekusi kode permintaan aplikasi saat ini objek tipe Magento\Backend\Model\Urlsedang dibuat dan membutuhkan implementasi untuk dependensi yang ditentukan konstruktor$routeConfig yang disebut jenis \Magento\Framework\App\Route\ConfigInterface.

Ini seperti mengatakan:

"Hai, Tn. ObjectManager! Setiap kali instance objek dari tipe Magento\Backend\Model\Urldiminta, silakan lihat definisi konstruktor kelasnya terlebih dahulu dan menganalisis ketergantungan yang ditentukan di dalamnya. Saya ingin Anda kemudian mencari di dalam final, digabung di.xmldari HTTP saat ini yang meminta konfigurasi untuk setiap dan setiap dependensi yang dikonfigurasi yang didefinisikan dalam konstruktor kelas Magento \ Backend \ Model \ Url . Anda memberi saya implementasi dependensi yang dikonfigurasi tersebut. "

adjco
sumber