Type hinting en PHP 5

19 de abril de 2008

Otra pregunta del curso de PHP5 se refirió a que ocurre si recibimos una clase en un método que ha definido una restricción de tipo, y esa clase es hija de la que se ha restringido. ¿Las acepta? ¿Podemos acceder a los métodos y propiedades de la clase hija?

La respuesta es que sí a las dos. La “restricción de tipo” lo único que hace es verificar que la clase de la instancia que se le pasa al método es la misma que se restringe, como si usáramos la función is_a(), que devuelve true tanto si una instancia es de una clase concreta o de sus clases derivadas.

Esta pregunta es normal cuando vienes de lenguajes con tipado fuerte. En PHP5 no existe este tipado fuerte, de hecho el “tipo” verdadero de todas las clases es sólo “Object”, nada más. La funcionalidad del “type hinting” solo supone una ayuda al programador a modo de filtro, por no implica que haya una conversión de tipo, o un moldeamiento, porque no existe tal tipo.

Si queremos saber si una instancia es exactamente de una clase concreta hay que utilizar la función get_class(), que devuelve el nombre de clase de la instancia que se pasa como parámetro.

Pongamos por ejemplo una clase Coche, y una clase derivada llamada Descapotable. Y tenemos un túnel de lavado, que debe cerrar las capotas de los coches descapotables antes de lavarlos:

[code lang=”php”]
class Coche
{
public function describe()
{
echo ‘Vehiculo de cuatro ruedas’;
}
}

class Descapotable extends Coche
{
public $CapotaRecogida=true;

public function describe()
{
parent::describe();
echo ‘El techo se recoge’;
echo ‘Capota: ‘.($this->CapotaRecogida?
‘La capota está recogida’:
‘La capota está desplegada’);
}
public function recogerCapota()
{
$this->CapotaRecogida=true;
}
public function desplegarCapota()
{
$this->CapotaRecogida=false;
}

}

function CleanCoche(Coche $coche)
{

// Si es un descapotable, cerramos la capota.
if(is_a($coche,Descapotable))
{
//Tenemos que cerrar la capota!!
if($coche->CapotaRecogida)
{
echo “INFO: Antes de lavar, cerramos la capota,
para no estropear el descapotable”;
$coche->desplegarCapota();
}
}

// no hay virtual ni override, se comporta
// como la instancia del objeto que és,
// no como Coche.
echo ‘INFO: Lavado coche:’ . get_class($coche) . ‘ ‘;
$coche->describe();

}

$a = new Coche();
$b = new Descapotable();

CleanCoche($a);
CleanCoche($b);
[/code]
Y la respuesta que se obtiene es la siguiente:
[code]
INFO: Lavado coche:Coche
Vehiculo de cuatro ruedas

INFO: Antes de lavar, cerramos la capota,
para no estropear el descapotable
INFO: Lavado coche:Descapotable
Vehiculo de cuatro ruedas
El techo se recoge
Capota: La capota está desplegada
[/code]
Como se puede observar en la respuesta, la función acepta tanto Coche como Descapotable. Dentro de la función verificamos si es de la clase Descapotable para cerrar la capota en caso de que la tenga abierta.

Siempre hay sobreescritura de métodos

Cuando llamamos al método describe() se ejecuta el correspondiente a nuestra instancia, no el de Coche. Llamar al método describe() del padre solo es posible desde dentro de Descapotable, usando parent::describe().

No se pueden sobrecargar métodos con type hinting

No podemos definir otra vez la función CleanCoche utilizando otro filtro de clase en los parámetros, ya que el interprete de PHP identifica esto como que hemos escrito dos funciones con el mismo nombre. No podemos separar la lógica del método en varias sobrecargas del método dependiendo de la clase, como se hace en C#. Todas las lógicas deberán estar dentro del mismo método, y usar una instrucción switch o if para ejecutar uno u otro código, tal como hemos hecho con Descapotable.

  • qrcode link