Diego Di Camillo

Base de tips para problemas comunes de los desarrolladores.



Conseguir sobrecarga de metodos en PHP 5 + | Emulación de sobrecarga de metodos en PHP 5

28Dic11

En PHP 5 (y sup) contamos con un método llamado __call(…) que se invoca justo cuando PHP se da cuenta que llamamos un método de clase que NO EXISTE o NO ESTÁ DEFINIDO. Gracias a esto, podemos emular sobrecarga de métodos, con lo cual el código es mucho más claro y auto-documentado.

Para aquellos que no sepan que es sobrecarga de métodos, en lenguajes fuertemente tipados, como Java, o C++ podemos tener un método que haga distintas cosas segun el TIPO o CANTIDAD de parémetros que le pasemos.

ejemplo en PHP podriamos tener :

$o = new testClass();
$p = new Class2();
var_dump($o->getAll());
var_dump($o->getAll($p));
var_dump($o->getAll($p, 'Hola'));

Como vemos el metodo getAll(…) está invocado 3 veces con distintos tipos y cantidades de paramnetros. Entonces decimos que esta sobrecargado
El concepto es devolverTodos pero con distintos condicionamientos o de distintas maneras.

Para emular esto podriamos definir la clase testClass de la siguiente manera:

class TestClass extends Model {

/** se ejecuta justo cuando no exite el metodo de clase */
private function __call($method_name, $arguments) {
    
	//la lista de metodos sobrecargados
	$accepted_methods = array("getAll", "test");
    	if(!in_array($method_name, $accepted_methods)) {
      		trigger_error("Metodo $method_name no existe", E_USER_ERROR);
    	}

    	//metodo sin argumentos
	    if(count($arguments) == 0) {
	      $this->$method_name();
	      
	      //metodo con 1 argumento
	    } elseif(count($arguments) == 1) {
	      $this->${$method_name.'1'}($arguments[0]);
	      
	      //metodo con 2 argumentos
	    } elseif(count($arguments) == 2) {
	      $this->${$method_name.'2'}($arguments[0], $arguments[1]);
	    
	    
	    //error +de 2 parametros, metodo no definido
	    } else {
	      return false;
	    }
    }


   function getAll(){
   
     /** algoritmo sin parametros **/
    }

   function getAll1($p1){
    
     /** algoritmo con 1 parametro **/
    }

   function getAll2($p1, $p2){
    
     /** algoritmo con 2 parametro **/
    }



    function test(){
     /** algoritmo sin parametros **/
    }


    function test1($p1){
      /** algoritmo con 1 parametro **/
    }
 
    function test2($p1,$p2){
      /** algoritmo con 2 parametro **/  
    }

  /*    ........  mas definiciones  */
}	

Como ves, en la clase nunca puedo poner dos funciones con el mismo nombre, pero la funcion __class despacha al método correcto segun la cantidad de parametros recibidos.
No es lo mas top , pero es lo que hay por ahora ….

Archivado en: Code Igniter, configuraciones, Frames php, General, Nuevas Tecnologias, PHP, Productos open source   |  9 Comentarios

9 comentarios a “Conseguir sobrecarga de metodos en PHP 5 + | Emulación de sobrecarga de metodos en PHP 5”  

Feed de este artículo URI para Trackbacks
  1. 1 Javier Corona en Mar 15th, 2013 dijo:

    Hola hermano, no se si ya haya salido otra mejor manera de hacer sobrecarga, algo que no sea emulado y más natural como se hace en java por ejemplo. Bueno en todo caso tu código, tal cual está no funciona. Ya lo hice funcionar checa el código comentado:

    <?php
    class TestClass{

    /** se ejecuta justo cuando no exite el metodo de clase */
    function __call($method_name, $arguments) {

    //la lista de metodos sobrecargados
    $accepted_methods = array("getAll", "test");

    if(!in_array($method_name, $accepted_methods)) {
    trigger_error("Metodo $method_name no existe», E_USER_ERROR);
    }

    if(count($arguments)==0){
    /*$this->$method_name();*/ /*No se por que, pero si lo dejas así y declaras getAll()
    y test() por más que llames las funciones con parametros
    siempre entrará a la función sin parametros, eso me pasó a mí*/
    $this->{$method_name.’0′}();//Concatené un 0, declare getAll0() y test0() y santo remedio
    }else if(count($arguments)==1){
    $this->{$method_name.’1′}($arguments[0]);/*Los $ antes de los {$metod_name están de más,
    Los tuve que quitar para que funcionara*/
    }else if(count($arguments)==2){
    $this->{$method_name.’2′}($arguments[0], $arguments[1]);
    }else{
    return false;
    }
    }

    //Imprimí contenido en todas las funciones para probar que funcionara

    function getAll0(){//Como mencione lo nombré como getAll0() y no como getAll()
    echo» metodo getAll() sin parámetros»;
    }

    function getAll1($p1){
    echo» metodo getAll() con 1 parámetro»;
    }

    function getAll2($p1, $p2){
    echo» metodo getAll() con 2 parámetros»;
    }

    function test0(){//Como mencione lo nombré como test0() y no como test()
    echo» metodo test() sin parámetros»;
    }

    function test1($p1){
    echo» metodo test() con 1 parámetro»;
    }

    function test2($p1,$p2){
    echo» metodo test() con 2 parámetros»;
    }

    }

    $sc = new TestClass();
    $sc->getAll();
    $sc->getAll(1);
    $sc->getAll(1,2);
    $sc->test();
    $sc->test(1);
    $sc->test(1,2);
    ?>

  2. 2 Javier Corona en Mar 15th, 2013 dijo:

    No se si sea más óptimo o no pero yo por mi cuenta lo modifiqué el function __call() y creí que era mejor usar switch en vez de if else if … Y me quedó así:

    function __call($method_name, $arguments) {

    //la lista de metodos sobrecargados
    $accepted_methods = array(«getAll», «test»);

    if(!in_array($method_name, $accepted_methods)) {
    trigger_error(«Metodo $method_name no existe», E_USER_ERROR);
    }
    else switch($counter = count($arguments)){
    case 0:
    $this->{$method_name.$counter}();
    break;
    case 1:
    $this->{$method_name.$counter}($arguments[0]);
    break;
    case 2:
    $this->{$method_name.$counter}($arguments[0], $arguments[1]);
    break;
    default:
    return false;
    }
    }

    Si, lo sustituyes en el otro código debe funcionar. Tengo las dos versiones funcionando, tengo los archivos .php, por si los quieres te los mando. Aunque creo que con un simple copy – paste, será más que suficiente.

  3. 3 Javier Corona 6 en Mar 15th, 2013 dijo:

    Hay algo más que quisera comentar, ya después de corregirlo, me di cuenta que en las funciones que se utiliza el return, no devuelve el valor, entra correctamente, comprobé que los valores llegan como deberían llegar y se pueden hacer operaciones con ellos, pero no se por qué razón no devuelve el valor, si guardas el retorno en una variable, es como si no hubieses guardado nada. Si gustas te puedo pasar un ejemplo de eso.

  4. 4 ddicami en Mar 15th, 2013 dijo:

    Excelente mejora. Gracias.

  5. 5 ddicami en Mar 15th, 2013 dijo:

    Lo voy a chequear, pero no deberia ser asi. EL metodo __call simplemente se INVOCA cuando el metodo al que llamas (normalmente) no existe, entonces este metodo se las arregla para saber que quieres hacer, y simplemente lo deribas.-

    No olvides dentro del metodo __call poner un return tambien!!!!!!

  6. 6 Carlos en Jul 4th, 2013 dijo:

    Aquí es donde te das cuenta que php es una basura…

  7. 7 ddicami en Jul 4th, 2013 dijo:

    Subjetivo comentario. Ya que lenguajes como JAVA , C++ , PARA WEB son lenguajes que requieren de mas tiempo, y los costos no lo pagan, con PHP puedes desarrollar applicaciones de embergadura (FACEBOOK) a tiempos reducidos y costos menores. Lo cual supera ppor lejos la eleccion del lenguaje a estos primeros.

  8. 8 kayetano en Ene 8th, 2014 dijo:

    Hola, aunque es un tema antiguo quisiera participar con otra alternativa.
    Tal y como está planteado el problema se pueden utilizar argumentos alternativos (http://php.net/manual/es/functions.arguments.php) para simular una sobre carga de la función o métodos.

  9. 9 ddicami en Ene 8th, 2014 dijo:

    Buen aporte, gracias!!

Enviando tu Comentario
Por favor espera

Deja una respuesta

Hubo un error con tu comentario, por favor intenta de nuevo.



Comparte este artículo

  • Menéame  Menéalo
  • del.icio.us  Enviar a Del.icio.us
  • Mi Yahoo!  Agregar a Mi Web 2.0
  • Furl  Guardar en Furl
 


wordpressk2openswitchyukei.netfeedwordpress