Ver Mensaje Individual
  #9 (permalink)  
Antiguo 18/05/2014, 14:35
Avatar de NSD
NSD
Colaborador
 
Fecha de Ingreso: mayo-2012
Ubicación: Somewhere
Mensajes: 1.332
Antigüedad: 12 años, 6 meses
Puntos: 320
Respuesta: APORTE: Emular polimorfismo y sobrecarga tipada de forma simple.

Bueno, veo que hubo varias sugerencias y criticas constructivas sobre esto, asi que aqui publico la nueva version que contempla todo lo que se planteo, y ademas, esta optimizada en comparacion a la anterior, la van a encontrar bastante flexible, aqui esta:

Código PHP:
Ver original
  1. <?php
  2.  namespace NS;
  3.  
  4.  class OverridableType extends \ReflectionObject
  5.  {
  6.     private $overload = array();
  7.     private static $overloadStatic = array();
  8.  
  9.     public function __construct()
  10.     {
  11.         parent::__construct($this);
  12.  
  13.         foreach ($this->getMethods() as $method)
  14.         {
  15.             $info = array_filter(array_map(function($val)
  16.                                             {
  17.                                                 $filter = trim(trim($val, '/*'));
  18.                                                 return ($filter ? explode(" ", $filter) : null);
  19.                                             }, explode("\n", $method->getDocComment())));
  20.             if($info)
  21.             {
  22.                 $tmp = array("params" => array());
  23.                 foreach($info as $directive)
  24.                 {
  25.                     switch($directive[0])
  26.                     {
  27.                         case "@overload" : $tmp["method"]   = $directive[1]; break;
  28.                         case "@count"    : $tmp["count"]    = $directive[1]; break;
  29.                         case "@param"    : $tmp["params"][] = strtolower($directive[1]); break;
  30.                         case "@default"  : $tmp["default"]  = $directive[1]; break;
  31.                     }
  32.                 }
  33.  
  34.                 if($method->isStatic())
  35.                 {
  36.                     if($tmp["default"])
  37.                     {
  38.                         if($tmp["count"])
  39.                             self::$overloadStatic[get_called_class()][$tmp["method"]][$tmp["count"]]["default"] = $tmp["default"];
  40.                         else
  41.                            self::$overloadStatic[get_called_class()][$tmp["method"]]["default"] = $tmp["default"];
  42.                     } else
  43.                         self::$overloadStatic[get_called_class()][$tmp["method"]][$tmp["count"]][] = array("types" => $tmp["params"], "name" => $method->getShortName());
  44.                 } else {
  45.                     if($tmp["default"])
  46.                     {
  47.                         if($tmp["count"])
  48.                             $this->overload[$tmp["method"]][$tmp["count"]]["default"] = $tmp["default"];
  49.                         else
  50.                             $this->overload[$tmp["method"]]["default"] = $tmp["default"];
  51.                     }
  52.                     else
  53.                         $this->overload[$tmp["method"]][$tmp["count"]][] = array("types" => $tmp["params"], "name" => $method->getShortName());
  54.                 }
  55.             }
  56.         }
  57.     }
  58.  
  59.     private static function getNameOverload($name, $args, $map)
  60.     {
  61.         if(isset($map[$name]))
  62.         {
  63.             $cant = count($args);
  64.             if(isset($map[$name][$cant]))
  65.             {
  66.                 foreach($map[$name][$cant] as $nro => $method)
  67.                 {
  68.                     if($nro !== "default")
  69.                     {
  70.                         $match = true;
  71.                         foreach($method["types"] as $tnro => $type)
  72.                         {
  73.                             $argType = gettype($args[$tnro]);
  74.                             if(!($argType == $type) and !($argType == 'object' && ($args[$tnro] instanceof $type)))
  75.                             {
  76.                                 $match = false;
  77.                                 break;
  78.                             }
  79.                         }
  80.                         if($match)
  81.                             return $method["name"];
  82.                     }
  83.                 }                
  84.                 if(isset($map[$name][$cant]["default"]))
  85.                     return $map[$name][$cant]["default"];
  86.                 else
  87.                     die("No se pudo resolver el metodo $name con $cant argumentos tipados ".implode(", ",array_map(function($val) { return gettype($val); }, $args)).".");            
  88.             } elseif(isset($map["default"]))
  89.                 return $map["default"];
  90.             else
  91.                 die("No se pudo resolver el metodo $name con $cant argumentos.");
  92.         } else
  93.             die("No se pudo resolver el metodo $name.");
  94.     }
  95.  
  96.     function __call($name, $args)
  97.     {
  98.         return call_user_func_array([$this, self::getNameOverload($name, $args, $this->overload)], $args);
  99.     }
  100.  
  101.     function __callStatic($name, $args)
  102.     {
  103.         return forward_static_call([$this, self::getNameOverload($name, $args, self::$overloadStatic[get_called_class()])], $args);
  104.     }
  105.  }
  106.  
  107.  // Y asi es como se implementa.
  108.  interface Vehicle
  109.  {
  110.      function run();
  111.  }
  112.  
  113.  namespace NSA;
  114.  
  115.  class Train implements \NS\Vehicle {
  116.     function run() {
  117.         echo 'chu-chua, chu-chua, chu-chua, ...<br />';
  118.     }
  119.  }
  120.  
  121.  namespace NSB;
  122.  
  123.  class Train implements \NS\Vehicle {
  124.     function run() {
  125.         echo 'chu-chub, chu-chub, chu-chub, ...<br />';
  126.     }
  127.  }
  128.  
  129.  namespace NS;
  130.  
  131.  class Car implements Vehicle {
  132.      function run() {
  133.          echo 'run, run, run, run, ...<br />';
  134.      }
  135.  }
  136.  
  137.  class Moto implements Vehicle {
  138.      function run() {
  139.          echo 'rrrrrrrrrrrrrrrrrrrr ...<br />';
  140.      }
  141.  }
  142.  
  143.  class Foto {
  144.      function sepia() {
  145.          echo 'me volvi sepia...<br />';
  146.      }
  147.  }
  148.  
  149.  class Test extends OverridableType
  150.  {
  151.     /**
  152.       @overload miMetodo
  153.       @count 0
  154.     */
  155.     public static function smethod()
  156.     {
  157.          echo("<br>Hola, no has ingresado nada de forma estatica<br>");
  158.     }
  159.    
  160.     /**
  161.       @overload miMetodo
  162.       @count 1
  163.       @param integer
  164.     */
  165.     public static function smethod1()
  166.     {
  167.          echo("<br>Hola, has ingresado: $unNumero estaticamente<br>");
  168.     }
  169.  
  170.     /**
  171.       @overload miMetodo
  172.       @count 0
  173.     */
  174.     public function method()
  175.     {
  176.          echo("<br>Hola, no has ingresado nada<br>");
  177.     }
  178.  
  179.     /**
  180.       @overload miMetodo
  181.       @count 1
  182.       @param integer
  183.     */
  184.     public function method1($unNumero)
  185.     {
  186.          echo("<br>Hola, has ingresado: $unNumero<br>");
  187.     }
  188.  
  189.     /**
  190.       @overload miMetodo
  191.       @count 1
  192.       @param string
  193.     */
  194.     public function method2($miString)
  195.     {
  196.         echo("<br>Hola, has ingresado: '$miString'<br>");
  197.     }
  198.  
  199.     /**
  200.       @overload miMetodo
  201.       @count 1
  202.       @param Train
  203.     */
  204.     public function method3($unTren)
  205.     {
  206.         echo("<br>Hola, gracias por el tren<br>");
  207.         $unTren->run();
  208.     }
  209.    
  210.     /**
  211.       @overload miMetodo
  212.       @count 1
  213.       @param NSA\Train
  214.     */
  215.     public function method3a($unTren)
  216.     {
  217.         echo("<br>Hola, gracias por el tren del namespace a<br>");
  218.         $unTren->run();
  219.     }
  220.    
  221.     /**
  222.       @overload miMetodo
  223.       @count 1
  224.       @param NSB\Train
  225.     */
  226.     public function method3b($unTren)
  227.     {
  228.         echo("<br>Hola, gracias por el tren del namespace b<br>");
  229.         $unTren->run();
  230.     }
  231.  
  232.     /**
  233.       @overload miMetodo
  234.       @count 1
  235.       @param NS\Car
  236.     */
  237.     public function method4($unAuto)
  238.     {
  239.         echo("<br>Hola, gracias por el auto<br>");
  240.         $unAuto->run();
  241.     }
  242.  
  243.     /**
  244.       @overload miMetodo
  245.       @count 1
  246.       @param NS\Vehicle
  247.     */
  248.     public function method5($unVehiculo)
  249.     {
  250.         echo("<br>Hola, gracias por el vehiculo<br>");
  251.         $unVehiculo->run();
  252.     }
  253.  
  254.     /**
  255.       @overload miMetodo
  256.       @count 1
  257.       @param Object
  258.     */
  259.     public function method6($unObjeto)
  260.     {
  261.         echo("<br>Hola, me diste un objeto: ".get_class($unObjeto).", muchas gracias.<br>");
  262.     }
  263.  
  264.     /**
  265.       @overload miMetodo
  266.       @count 2
  267.       @param integer
  268.       @param string
  269.     */
  270.     public function method7($unNumero, $miString)
  271.     {
  272.          echo("<br>Hola, has ingresado un numero: $unNumero y un string '$miString'<br>");
  273.     }
  274.  
  275.     /**
  276.       @overload miMetodo
  277.       @count 2
  278.       @param string
  279.       @param integer
  280.     */
  281.     public function method8($miString, $unNumero)
  282.     {
  283.         echo("<br>Hola, has ingresado un string: '$miString' y un numero $unNumero<br>");
  284.     }
  285.    
  286.     /**
  287.       @overload miMetodo
  288.       @count 2
  289.       @param integer
  290.       @param integer
  291.     */
  292.     public function method9($unNumero, $otroNumero)
  293.     {
  294.         echo("<br>Hola, has ingresado un numero: $unNumero y un numero $otroNumero<br>");
  295.     }
  296.  }
  297.  
  298.  class Testb extends Test
  299.  {    
  300.     /**
  301.       @overload miMetodo
  302.       @count 2
  303.       @param string
  304.       @param integer
  305.     */
  306.     public function method8($miString, $unNumero)
  307.     {
  308.         echo("<br>Hola, has ingresado un string: '$miString' y un numero $unNumero pero en una subclase.<br>");
  309.     }
  310.  }
  311.  
  312.  $test = new Test;
  313.  
  314.  $test->miMetodo();
  315.  $test->miMetodo(1);
  316.  $test::miMetodo();
  317.  $test::miMetodo(1);
  318.  $test->miMetodo('hola');
  319.  $test->miMetodo(99, 'hola');
  320.  $test->miMetodo('hola', 1);
  321.  $test->miMetodo(1, 2);
  322.  $test->miMetodo(new Car);
  323.  $test->miMetodo(new \NSA\Train);
  324.  $test->miMetodo(new \NSB\Train);
  325.  $test->miMetodo(new Moto);
  326.  $test->miMetodo(new Foto);
  327.  
  328.  $testb = new Testb;
  329.  $testb->miMetodo('hola', 1);

produce esta salida:
Cita:

Hola, no has ingresado nada

Hola, has ingresado: 1

Hola, has ingresado: 'hola'

Hola, has ingresado un numero: 99 y un string 'hola'

Hola, has ingresado un string: 'hola' y un numero 1

Hola, has ingresado un numero: 1 y un numero 2

Hola, gracias por el auto
run, run, run, run, ...

Hola, gracias por el tren del namespace a
chu-chua, chu-chua, chu-chua, ...

Hola, gracias por el tren del namespace b
chu-chub, chu-chub, chu-chub, ...

Hola, gracias por el vehiculo
rrrrrrrrrrrrrrrrrrrr ...

Hola, me diste un objeto: NS\Foto, muchas gracias.

Hola, has ingresado un string: 'hola' y un numero 1 pero en una subclase.
__________________
Maratón de desafíos PHP Junio - Agosto 2015 en FDW | Reglamento - Desafios