Ver Mensaje Individual
  #1 (permalink)  
Antiguo 10/09/2011, 14:58
Avatar de andresdzphp
andresdzphp
Colaborador
 
Fecha de Ingreso: julio-2011
Ubicación: $this->Colombia;
Mensajes: 2.749
Antigüedad: 12 años, 9 meses
Puntos: 793
Nuevos "Traits" PHP 5.4.0+

Nuevos "Traits" (PHP 5.4.0+)

Un post con el fin de actualizar la gente con nuevas características de PHP orientado a objetos.

Desde PHP 5.4.0, PHP implementa una metodología de reutilización de código llamada Traits.

Los traits (rasgos) son un mecanismo de reutilización de código en lenguajes de herencia simple, como PHP. El objetivo de un trait es el de reducir las limitaciones propias de la herencia simple permitiendo que los desarrolladores reutilicen a voluntad conjuntos de métodos sobre varias clases independientes y pertenecientes a clases jerárquicas distintas. La semántica a la hora combinar Traits y clases se define de tal manera que reduzca su complejidad y se eviten los problemas típicos asociados a la herencia múltiple y a los Mixins.

Un Trait es similar a una clase, pero con el único objetivo de agrupar funcionalidades muy específicas y de una manera coherente. No se puede instanciar directamente un Trait. Es por tanto un añadido a la herencia tradicional, y habilita la composición horizontal de comportamientos; es decir, permite combinar miembros de clases sin tener que usar herencia.

Ejemplo de Trait

Código PHP:
Ver original
  1. <?php
  2. trait ezcReflectionReturnInfo {
  3.     function getReturnType() { /*1*/ }
  4.     function getReturnDescription() { /*2*/ }
  5. }
  6.  
  7. class ezcReflectionMethod extends ReflectionMethod {
  8.     use ezcReflectionReturnInfo;
  9.     /* ... */
  10. }
  11.  
  12. class ezcReflectionFunction extends ReflectionFunction {
  13.     use ezcReflectionReturnInfo;
  14.     /* ... */
  15. }
  16. ?>

Precedencia

Los miembros heredados de una clase base se sobrescriben cuando se inserta otro miembro homónimo desde un Trait. De acuerdo con el orden de precedencia, los miembros de la clase actual sobrescriben los métodos del Trait, que a su vez sobrescribe los métodos heredados.

Ejemplo de Orden de Precedencia

Cita:
Se sobrescribe un miembro de la clase base con el método insertado en MiHolaMundo a partir del Trait DecirMundo. El comportamiento es el mismo para los métodos definidos en la clase MiHolaMundo. Según el orden de precedencia los métodos de la clase actual sobrescriben los métodos del Trait, a la vez que el Trait sobrescribe los métodos de la clase base.
Código PHP:
Ver original
  1. <?php
  2. class Base {
  3.   public function decirHola() {
  4.     echo '¡Hola ';
  5.   }
  6. }
  7.  
  8. trait DecirMundo {
  9.   public function decirHola() {
  10.     parent::decirHola();
  11.     echo 'Mundo!';
  12.   }
  13. }
  14.  
  15. class MiHolaMundo extends Base {
  16.   use DecirMundo;
  17. }
  18.  
  19. $o = new MiHolaMundo();
  20. $o->decirHola();
  21. ?>

El resultado del ejemplo sería: ¡Hola Mundo!

Multiples Traits

Se pueden insertar múltiples Traits en una clase, mediante una lista separada por comas en la sentencia use.

Código PHP:
Ver original
  1. <?php
  2. trait Hola {
  3.   public function decirHola() {
  4.     echo 'Hola ';
  5.   }
  6. }
  7.  
  8. trait Mundo {
  9.   public function decirMundo() {
  10.     echo ' Mundo';
  11.   }
  12. }
  13.  
  14. class MiHolaMundo {
  15.   use Hola, Mundo;
  16.   public function decirAdmiración() {
  17.     echo '!';
  18.   }
  19. }
  20.  
  21. $o = new MiHolaMundo();
  22. $o->decirHola();
  23. $o->decirMundo();
  24. $o->decirAdmiración();>
  25. ?>

El resultado del ejemplo sería: Hola Mundo!

Resolución de Conflictos

Si dos Traits insertan un método con el mismo nombre, se produce un error fatal, siempre y cuando no se haya resuelto explicitamente el conflicto.

Para resolver los conflictos de nombres entre Traits en una misma clase, se debe usar el operador insteadof para elejir unívocamente uno de los métodos conflictivos.

Como esto sólo permite excluir métodos, se puede usar el operador as para permitir incluir uno de los métodos conflictivos bajo otro nombre.

Ejemplo Resolución de Conflictos

Cita:
En este ejemplo, Talker utiliza los traits A y B. Como A y B tienen métodos conflictos, se define el uso de la variante de smallTalk del trait B, y la variante de bigTalk del traita A.

Aliased_Talker hace uso del operador as para poder usar la implementación de bigTalk de B, bajo el alias adicional talk.
Código PHP:
Ver original
  1. <?php
  2. trait A {
  3.   public function smallTalk() {
  4.     echo 'a';
  5.   }
  6.   public function bigTalk() {
  7.     echo 'A';
  8.   }
  9. }
  10.  
  11. trait B {
  12.   public function smallTalk() {
  13.     echo 'b';
  14.   }
  15.   public function bigTalk() {
  16.     echo 'B';
  17.   }
  18. }
  19.  
  20. class Talker {
  21.   use A, B {
  22.     B::smallTalk insteadof A;
  23.     A::bigTalk insteadof B;
  24.   }
  25. }
  26.  
  27. class Aliased_Talker {
  28.   use A, B {
  29.     B::smallTalk insteadof A;
  30.     A::bigTalk insteadof B;
  31.     B::bigTalk as talk;
  32.   }
  33. }
  34. ?>

Modificando la Visibilidad de los Métodos

Al usar el operador as, se puede también ajustar la visibilidad del método en la clase exhibida.

Código PHP:
Ver original
  1. <?php
  2. trait HolaMundo {
  3.   public function decirHola() {
  4.     echo 'Hola Mundo!';
  5.   }
  6. }
  7.  
  8. class MiClase1 {
  9.   use HolaMundo { decirHola as protected }
  10. }
  11.  
  12. class MiClase2 {
  13.   use HolaMundo { hacerHolaMundo as private decirHola }
  14. }
  15. ?>

Traits Compuestos de Traits

Al igual que las clases, los Traits también pueden hacer uso de otros Traits. Al usar uno o más traits en la definición de un trait, éste puede componerse parcial o completamente de miembros de finidos en esos otros traits.

Código PHP:
Ver original
  1. <?php
  2. trait Hola {
  3.   public function decirHola() {
  4.     echo 'Hola ';
  5.   }
  6. }
  7.  
  8. trait Mundo {
  9.   public function decirMundo() {
  10.     echo 'Mundo!';
  11.   }
  12. }
  13.  
  14. trait HolaMundo {
  15.   use Hola, Mundo;
  16. }
  17.  
  18. class MiHolaMundo {
  19.   use HolaMundo;
  20. }
  21.  
  22. $o = new MiHolaMundo();
  23. $o->decirHola();
  24. $o->decirMundo();
  25. ?>

El resultado del ejemplo sería: Hola Mundo!

Miembros Abstractos de Traits

Los traits soportan el uso de métodos abstractos para imponer requisitos a la clase a la que se exhiban.

Código PHP:
Ver original
  1. <?php
  2. trait Hola {
  3.   public function decirHolaMundo() {
  4.     echo 'Hola'.$this->obtenerMundo();
  5.   }
  6.   abstract public function obtenerMundo();
  7. }
  8.  
  9. class MiHolaMundo {
  10.   private $mundo;
  11.   use Hola;
  12.   public function obtenerMundo() {
  13.     return $this->mundo;
  14.   }
  15.   public function asignarMundo($val) {
  16.     $this->mundo = $val;
  17.   }
  18. }
  19. ?>

Miembros Estáticos en Traits

Los métodos de un trait pueden referenciar a variables estáticas, pero no puede ser definido en el trait. Los traits, sin embargo, pueden definir método estáticos a la clase a la que se exhiben.

Código PHP:
Ver original
  1. <?php
  2.   trait Contador {
  3.     public function inc() {
  4.       static $c = 0;
  5.       $c = $c + 1;
  6.       echo "$c\n";
  7.     }
  8.   }
  9.  
  10.   class C1 {
  11.     use Contador;
  12.   }
  13.  
  14.   class C2 {
  15.     use Contador;
  16.   }
  17.  
  18.   $o = new C1(); $o->inc(); // echo 1
  19.   $p = new C2(); $p->inc(); // echo 1
  20. ?>

Código PHP:
Ver original
  1. <?php
  2.   trait Singleton {
  3.     public static function getInstance() { ... }
  4.   }
  5.  
  6.   class MiSingleton extends SomeUnrelatedSuperClass {
  7.     use Singleton;
  8.   }
  9.  
  10.   MiSingleton::getInstance();
  11. ?>

Espero que les haya gustado, a mi me parece interesante el tema, aunque no muy claro todavía.

Más información en nuestro querido manual:

http://php.net/manual/es/language.oop5.traits.php

Saludos
__________________
Si sabemos como leer e interpretar el manual será mucho más fácil aprender PHP. En lugar de confiar en ejemplos o copiar y pegar - PHP