En éste módulo hablamos acerca de qué son y para qué sirven los Traits en PHP.
Transcripción
Hola, mi nombre es Alan Chavez. Autor del blog alanchavez.com. Y hoy vas a aprender que son los Traits en PHP y para qué sirven.
La palabra Trait en español significa Rasgo o característica. Es decir, algo que distingue una cosa de otra.
Dentro del contexto de la programación, un Trait es un concepto híbrido entre una clase y una interfaz. Específicamente en PHP, los Traits fueron introducidos en PHP 5.4 y sirven para dos cosas: (click)
Es que determinan lo que una clase debe hacer (tal y como las interfaces) Proveen una implementación modular (tal y como las clases)
Los Traits son útiles porque a veces dos objetos completamente diferentes, comparten un subconjunto de características en común, y no existe una manera sencilla de modelar esa situación dentro de PHP, ya que PHP utiliza el modelo clásico de herencia.
El modelo clásico de herencia, es en donde existe una clase raíz también conocida como clase padre o super clase. Y una sub clase, o clase hija; que es una versión especializada de la super clase.
Dentro de éste modelo, Las clases padre implementan un conjunto de propiedades y métodos que todas las clases hijas heredan automáticamente.
El modelo clásico de herencia, sirve para modelar -casi- un sinnúmero de situaciones de la vida real. El ejemplo más usado en la literatura es el de modelar la clasificación de los animales. (click)
En este ejemplo, podemos ver que “Animal" es una interfaz. Y simplemente define lo que todos los animales tienen en común. En éste caso, la interfaz Animal dice que todos los animales nacen, crecen, se reproducen y se mueren.
Si descendemos un nivel, encontramos las clases Abstractas Vertebrado y Invertebrado. Una clase abstracta es aquella que no se debe instanciar. Es decir, no es posible que exista un objeto “Vertebrado” directamente, las clases abstractas son automática
clases padre, ya que una subclase debe extender la clase abstracta para poder heredar sus métodos y propiedades.
Si no estás muy familiarizado con la Programación orientada a objetos, de manera muy sencilla. Una interfaz es un archivo que solamente define los métodos que una clase debe implementar, pero no determina los detalles de implementación; es decir: La interfaz
animal simplemente dicta que los metodos “nacer, crecer, reproducir y morir” deben existir en las clases que implementen la interfaz, pero no dicta COMO deben ser implementados. En otras palabras. Las interfaces no se pueden instanciar, es decir no
puedes obtener un objeto de ellas y además las funciones dentro de una interfaz deben estar vacías. De lo contrario no sería una interfaz.
Por otro lado, las clases abstractas proveen los detalles de implementación, pero tampoco pueden ser instanciadas. Para poder utilizar los métodos de una clase abstracta, tienes que extender la clase abstracta e instanciar la subclase que hereda los métodos
de la clase abstracta y llamar el método que necesites.
En el ejemplo anterior, Vertebrado e Invertebrad son clases abstractas, y definen metodos y propiedades que todas las subclases deben tener.
Por ejemplo, los animales vertebrados tienen huesos, y los animales invertebrados tienen hemocianina.
Si descendemos un nivel más, podemos encontrar las clases especializadas Mamifero, Reptil, Equinodermo y Molusco. Éstas clases son clases comunes y corrientes, pero si observas el modelo clásico de herencia, podemos extraer mucha información acerca de
que son y para que sirven, sin necesidad de invertir demasiado tiempo.
En éste caso, podemos encontrar las diferencias automáticamente entre las clases y puedes ver que los Mamiferos tienen pelo, los reptiles tienen escamas, los equinodermos tienen caparazón y los moluscos tienen radulas.
Como los mamiferos y los reptiles son vertebrados, ambos tienen huesos. De la misma forma, como los moluscos y los equinodermos son invertebrados, ambos tienen hemocianina.
Finalmente, todos son Animales, por lo que todos nacer, crecen, se reproducen y se mueren.
Ése es el modelo clásico de herencia, y funciona muy bien para modelar un sinnúmero de situaciones. Sin embargo, no es perfecto.
Puedes encontrar las diferencias entre éstos dos animales?
Bueno empezando por lo obvio; uno es un pulpo y el otro es un cocodrilo. (click) El pulpo es invertebrado; (click) el cocodrilo es vertebrado. El pulpo es un molusco; (click) el cocodrilo es un reptil El pulpo tiene hemocianina; (click) el cocodrilo tiene
escamas El pulpo tiene radula; (click) el cocodrilo tiene huesos.
Sin embargo; el pulpo y el cocodrilo tienen algo en común. Ambos son ovíparos!
¿Cómo modelamos el problema? Si recuerdas, la clase Reptil y Molusco no tienen una clase padre en común. Reptil extiende la clase Vertebrado, y Molusco extiende la clase Invertebrado.
Si solamente estuviéramos modelando los invertebrados sería un problema sencillo de resolver, ya que todos los invertebrados son ovíparos. Sin embargo, no podemos decir lo mismo de todos los vertebrados.
Podríamos utilizar una Interfaz, y hacer que todos los animales ovíparos implementen la interfaz. Sin embargo, si recuerdas que mencioné anteriormente, las interfaces simplemente determinan lo que una clase debe hacer, pero no dictan como debe hacerlo.
Por lo tanto, resolver este problema a través de interfaces significa duplicar mucho código a través de la aplicación.
Podrías crear una clase padre, pero PHP no soporta herencia múltiple y la clase Reptil y Molusco ya tienen una clase padre por lo que no es una solución viable. Podrías inyectar la dependencia Ovíparo dentro del constructor de la clase, pero esa solución
empieza a complicar el diseño aún más.
Y es por eso que los Traits en PHP son necesarios. Al inicio de éste video mencioné que los Traits sirven para modelas problemas en donde dos clases que no se encuentran relacionadas, puedan compartir un conjunto de propiedades y métodos con facilidad.
En éste caso, los metodos y propiedades de un Ovíparo pertenecen a un Trait.
La sintaxis de los traits es muy sencilla, si te das cuenta, se define tal y como una clase. Los trait pueden tener métodos y propiedades privados, públicos y protegidas.
Como puedes ver, son relativamente sencillos de implementar.
Aqui tenemos más código de ejemplo.
En la parte superior de la pantalla estoy definiendo el Trait ovíparo con la propiedad “huevos" y su respectivo getter. En la parte inferior izquierda podemos ver la definición de la clase Reptil, que hereda los métodos y propiedades de la clase Abstracta
vertebrado. Y justo debajo de la definición de la clase podemos ver que indicandole al interprete de PHP, que la clase Reptil hace uso del Trait Oviparo.
Para utilizar Traits en una clase, se hace a través de la palabra clave “use”. La palabra “use" en PHP tiene dos significados.
Cuando se utiliza fuera de la definición de una clase, la palabra “use" tiene un uso similar al de “include" o “require" y le indica al interprete de PHP que clases se van a utilizar dentro de ese archivo.
Sin embargo, cuando se utiliza DENTRO de la definición de una clase, la palabra “use" indica que se está utilizando un Trait.
En la parte inferior derecha, podemos ver que en éste caso la clase abstracta Invertebrado es la que indica el uso del Trait Oviparo. Ya que la biología nos dice que todos los invertebrados son Ovíparos.
En la parte inferior derecha, podemos ver que en éste caso la clase abstracta Invertebrado es la que indica el uso del Trait Oviparo. Ya que la biología nos dice que todos los invertebrados son Ovíparos.
En ésta pantalla podemos ver, nuevamente la versatilidad de la palabra “use”. Como mencioné anteriormente, en este ejemplo la palabra “use" le está indicando al Interprete de PHP que se van a utilizar las clases Reptil y Molusco.
El objeto cocodrilo crea una instancia de la clase Reptil, y puedes ver que el objeto cocodrilo puede llamar al método “getHuevos" que pertenece al Trait oviparo.
Puedes ver un comportamiento similar en el objeto “pulpo” que está creando una instancia de la clase Molusco.
Sin embargo! Los Traits no forman parte del modelo clásico de herencia. El interprete de PHP, durante la interpretación del script, copia y pega el contenido de un Trait dentro de una clase. Por lo que el interprete no provee ningún mecanismo para prevenir
problemas de colisiones, o problemas en donde el Trait asuma que un método o una propiedad existe en la clase donde se está incluyendo.
Con esto damos por concluído el modulo de Traits.
El link hacia el código de ejemplo se encuentra en la descripción de éste video, es un link a un repositorio público de Github.
Y si te gustó éste video, compártelo con tus amigos programadores, suscríbete a mi canal y no olvides visitar mi blog alanchavez.com donde regularmente escribo acerca de programación y freelancing.