¿Cuál es la diferencia entre type y virtualType?

41

En el di.xmlque viene con Magento2 hay un nodo typey un nodo virtualType. Mi pregunta es: ¿qué es esto virtualTypey en qué caso debería usarse en lugar de type?

En algunos lugares parece un enlace simbólico o reescribir:

<virtualType name="Magento\Core\Model\Session\Storage" type="Magento\Framework\Session\Storage">

Cuando una ruta completa se convierte en otra, pero en otros lugares parece usarse como una forma de definir un alias más corto.

<virtualType name="lessFileSourceBase" type="Magento\Framework\View\File\Collector\Base">
David modales
fuente
3
No tengo idea (aún) lo que incluso significan, pero se puede empezar a cavar desde aquí: Magento\Framework\ObjectManager\Config\Mapper\Dom::convert. Hay una switchdeclaración allí en alguna parte.
Marius
Gracias @Marius, también me pregunto si lessFileSourceBasese limita al xml o si eso también se puede usar afuera. Supongo que mejor me cavo.
David Manners

Respuestas:

84

Los tipos virtuales son una forma de inyectar diferentes dependencias en las clases existentes sin afectar a otras clases.

Por ejemplo, la Magento\Framework\Session\Storageclase toma un $namespaceargumento en su constructor, que por defecto es el valor 'predeterminado', y podría usar la typedefinición para cambiar el espacio de nombres a 'núcleo'.

<type name="Magento\Framework\Session\Storage">
    <arguments>
        <argument name="namespace" xsi:type="string">core</argument>
    </arguments>
</type>

La configuración anterior haría que todas las instancias Magento\Framework\Session\Storagetengan un espacio de nombres de 'núcleo'. El uso de un tipo virtual permite crear el equivalente de una subclase, donde solo la subclase tiene los valores de argumento alterados.

En el código base vemos las siguientes dos configuraciones:

<virtualType name="Magento\Core\Model\Session\Storage" type="Magento\Framework\Session\Storage">
    <arguments>
        <argument name="namespace" xsi:type="string">core</argument>
    </arguments>
</virtualType>

<type name="Magento\Framework\Session\Generic">
    <arguments>
        <argument name="storage" xsi:type="object">Magento\Core\Model\Session\Storage</argument>
    </arguments>
</type>

El primer fragmento crea un tipo virtual para el Magento\Core\Model\Session\Storageque altera el espacio de nombres, y el segundo inyecta el tipo virtual Magento\Framework\Session\Generic. Esto permite Magento\Framework\Session\Genericser personalizado sin afectar otras clases que también declaran una dependencia enMagento\Framework\Session\Storage

Chris O'Toole
fuente
Muchas gracias @Chris finalmente alguna justificación lógica que encontré
Suman-PHP4U
Eso fue simple y la mejor demostración.
Umar
Esta respuesta es mejor que el documento oficial de Magento
Suman-PHP4U
<type>está usando una clase virtual que en realidad no existe. De esta manera, la modificación del argumento virtualTypetendrá efecto solo cuando se inicialice la clase que usa virtualType, que es Magento\Framework\Session\Genericen el ejemplo
Arif Ahmad,
21

Otra forma de entender los tipos virtuales:

Digamos que tiene una clase \Class1, que tiene el siguiente constructor:

public function __construct(\Class2 $argOfClass1){...}

Y \Class2tiene el siguiente constructor:

public function __construct(\Class3 $argOfClass2){...}

Ahora, desea cambiar el tipo de $argOfClass2de \Class3a \Class4, pero solo cuando \Class2se usa como $argOfClass1.

La forma "antigua" de hacerlo sería agregar lo siguiente en di.xml-

<type name="Class1">
    <arguments>
         <argument name="argOfClass1" xsi:type="object">Class5</argument>
    </arguments>
</type>

donde \Class5es lo siguiente:

class \Class5 extends \Class2{
    public function __construct(\Class4 $argOfClass2){...}
}

En lugar de usarlo de esta manera, puede usar los tipos virtuales para lograr lo mismo, agregando lo siguiente a di.xml:

<virtualType name="Class5" type="Class2">
    <arguments>
        <argument name="argOfClass2" xsi:type="string">Class4</argument>
    </arguments>
</virtualType>

<type name="Class1">
    <arguments>
         <argument name="argOfClass1" xsi:type="object">Class5</argument>
    </arguments>
</type>

Como puede ver, usar el tipo virtual le ahorró el trabajo de creación Class5.

Para mayor referencia, sugiero leer el artículo de Alan Storm sobre los tipos virtuales en Magento2: http://alanstorm.com/magento_2_object_manager_virtual_types/

NoamN
fuente
1
buena expansión,
Anand Ontigeri
Fácil de comprender. Gracias por compartir un ejemplo tan básico.
Kalyan Chakravarthi V
10

En el mismo di.xmlarchivo encontré que lessFileSourceBasese pasa como argumento para lessFileSourceBaseFilteredeso se pasa como argumento para lessFileSourceBaseSortedeso se pasa como argumento para type Magento\Framework\Less\File\Collector\Aggregated.

No encontré ninguna otra aparición de lessFileSourceBase(o lessFileSource) en otro archivo, excepto di.xmldel módulo central. Solo en algunos archivos de caché, pero no son importantes

Supongo que si no va a usar el tipo virtual en una clase PHP, pero solo en los diarchivos xml, no es necesario que parezca un nombre de clase y puede usar un alias.

Pero esto es solo pura especulación.
Será "divertido" intentar crear una clase e inyectar una instancia en su constructor lessFileSourceBasepara ver cómo se comporta.

Marius
fuente
1
te perdiste las citas alrededor de la palabra diversión;)
David Manners
1
@DavidManners. Correcto. Lo arreglé. :)
Marius
@Marius: si altera el \Magento\Framework\Session\Genericarchivo de origen para depender Magento\Core\Model\Session\Storagede StorageInterfaceél, debería obtener una excepción 'Clase Magento \ Core \ Model \ Session \ Storage no existe'. La razón es que ObjectManager no crea una instancia de virtualType, sino que solo la usa para determinar qué argumentos proporcionar para el constructor del tipo concreto al que hace referencia la definición de virtualType ( Magento\Framework\Session\Storagepara el ejemplo anterior).
Chris O'Toole
Puede ver esto en Factory , donde $requestedTyperepresenta el tipo virtual y se usa para recopilar argumentos, pero $typees el tipo concreto al que se asigna virtualType y se usa para la llamada de instanciación de objetos.
Chris O'Toole
Entonces, incluso si lessFileSourceBaseestuviera en un estilo de tipo de espacio de nombres \ clase más, no permitiría la referencia directa de otra clase de php, solo para inyección a través de di.xml
Chris O'Toole