Plantilla:PHP/Sobrecarga
De WikiEducator
Sobrecarga
Es un concepto muy importante y básico en la programación orientada a objetos. La sobrecarga es una concreción del principio de polimorfismo.
|
- Sin embargo, este aspecto en PHP no es del todo intuitivo: no existe la sobrecarga como la entendemos en otros lenguajes.
- No obstante, disponemos de técnicas para poder simular la sobrecarga.
- En muchos casos resulta fundamental, especialmente al sobrecargar el constructor de una clase.
- Para simular la sobrecarga en PHP, aprovechamos que una variable que no tenga valor se considera del tipo null.
- Lo veremos con una serie de ejemplos para dejar claro este concepto.
- Tomamos como ejemplo una función:
Ejemplo
| |
function verTipoParametros($a = null, $b = null, $c = null){ echo "Primer parámetro: "; var_dump($a); echo "Segundo parámetro: "; var_dump($b); echo "Tercer parámetro: "; var_dump($c); }
|
- Ahora la invocamos de diferentes maneras y observamos el resultado:
Invocar sin parámetros reales
| |
echo "Invocando a <strong>verTipoParametros()</strong><hr />"; verTipoParametros();
|
Invocar con 1 parámetro real
| |
echo "Invocando a <strong>verTipoParametros(5)</strong><hr />"; verTipoParametros(5);
|
Invocar con 2 parámetros reales
| |
echo "Invocando a <strong>verTipoParametros(5,7)</strong><hr />"; verTipoParametros(5,7);
|
Invocar con 3 parámetros reales
| |
echo "Invocando a <strong>verTipoParametros('pedro',5,9)</strong><hr />"; verTipoParametros('pedro',5,9);
|
Invocar con 3 parámetros reales, uno de ellos un array
| |
echo "Invocando a <strong>verTipoParametros([1,4,'maría'], true, 'sonia')</strong><hr />"; verTipoParametros([1,4,'maría'], true, 'sonia');
|
Sobrecargando el constructor
- Usando esta forma de trabajar, vamos a sobrecargar el constructor de una clase.
- Tomemos como ejemplo una clase Racional. Un número racional es un objeto que tiene numerador y denominador.
- Queremos permitir crear el objeto de distintas formas:
$r1 = new Racional("8/5"); /* 8/5 */ $r2 = new Racional(5,4); /* 5/4 */ $r3 = new Racional(5); /* 5/1 */ $r4 = new Racional(); /* 1/1 */
- Necesitamos que el constructor pueda responder a todas las situaciones.
- Aplicando los conceptos vistos, solo tenemos que comprobar de qué tipo son los parámetros.
Tip: Recordar que null también es un tipo.
- Vemos que podemos tener 0, 1 o 2 parámetros.
Por lo tanto, el constructor tendrá dos parámetros opcionales.
public function __construct($num = 1, $den = 1) { ... }
- Especificamos el código de cómo se podría implementar:
class Racional { private $num; private $den; public function __construct($num = 1, $den = 1) { // opciones: // new Racional() => 1/1 // new Racional(5) => 5/1 // new Racional("5/2") => 5/2 // new Racional(5,2) => 5/2 // Otra situación: no se instancia correctamente if (is_string($num)) { $numero = explode("/", $num); $num = $numero[0]; $den = $numero[1]; } $this->num = $num; $this->den = $den; } /* Método para visualizar el objeto como cadena de caracteres */ public function __toString() { return ($this->num . "/" . $this->den); } // Métodos privados para asignar valores según la forma de invocación private function racionalNum($num) { $this->num = $num; $this->den = 1; } /** * @param string $num número racional del tipo "a/b" * Hay muchas formas de poder descomponer esa cadena en dos números. */ public function racionalCadena($num) { $partes = explode("/", $num); $this->num = (int) $partes[0]; $this->den = (int) $partes[1]; } public function racionalVacio() { $this->num = 1; $this->den = 1; } /* En este caso, si los valores son incorrectos, asigno el racional 1/1 */ public function racionalNumDen($num, $den) { if (is_numeric($num) && is_numeric($den)) { $this->num = $num; $this->den = $den; } else { $this->num = 1; $this->den = 1; } } }
- Esta sería una posibilidad, pero podemos crear un código más compacto.
En la siguiente versión inicializamos los parámetros con un valor por defecto (1). Posteriormente, si el primer parámetro es una cadena, se divide en numerador y denominador. Hecho esto, solo queda asignar los valores a los atributos.
public function __construct($num = 1, $den = 1){ if (is_string($num)){ $numero = explode("/", $num); $num = $numero[0]; $den = $numero[1]; } $this->num = $num; $this->den = $den; }
- Probamos este constructor con el siguiente código:
$a = new Racional(); $b = new Racional(5); $c = new Racional(5,6); $d = new Racional("6/6"); echo "Valor del racional \$a = $a <br />"; echo "Valor del racional \$b = $b <br />"; echo "Valor del racional \$c = $c <br />"; echo "Valor del racional \$d = $d <br />";
- Mostrando los siguientes resultados:
Valor del racional $a = 1/1 Valor del racional $b = 5/1 Valor del racional $c = 5/6 Valor del racional $d = 6/6
Sobrecarga con __call(...)
- Otra forma de lograr un comportamiento similar es usando el método mágico __call($funcion, $parametros).
Tip: El método mágico __call(...) se ejecuta cuando invocamos un método que no existe en la clase.
- Queremos usar un método llamado asigna() que nos permita cambiar el valor de un racional.
- La forma de aportar el nuevo valor será la misma que la de construir el objeto.
$r1 = new Racional(); // construye el objeto 1/1 $r1->asigna("6/4"); // ahora el objeto vale 6/4 $r1->asigna(); // ahora el objeto vale 1/1 $r1->asigna(8); // ahora el objeto vale 8/1 $r1->asigna(124, 6); // ahora el objeto vale 124/6
- La forma de proceder será usando los métodos privados creados anteriormente.
- El siguiente código implementa la solución:
public function __call($metodo, $argumentos) { if ($metodo == "asigna") { switch (count($argumentos)) { case 0: $this->racionalVacio(); break; case 2: $this->racionalNumDen($argumentos[0], $argumentos[1]); break; case 1: if (is_int($argumentos[0])) { $this->racionalNum($argumentos[0]); } else { $this->racionalCadena($argumentos[0]); } break; } } }





