Modelo de objetos en PHP5

Control de acceso revisitado - protected

Atributos y métodos protegidos

Los atributos y métodos marcados como protected en una determinada clase, son accesibles desde el interior de sus clases derivadas, pero no son accesibles desde el exterior.

Para ver el comportamiento en profundidad se muestra una nueva versión de la clase Vehiculo:

class Vehiculo
{
//// atributos publicos (no recomendable)
public $peso;
public
$color1 = "rojo";

//// atributos protegidos (acceso a clases derivadas)
protected $color2 = "rojo_oscuro";
protected
$potencia;

//// atributos privados (uso interno)
private $relPesoPotencia;
private
$color3 = "rojo_claro";


//// constructor
function __construct($potencia,$peso)
{
$this->potencia = $potencia;
$this->peso = $peso;

//// calcula la relacion peso/potencia para este vehiculo
$this->relacionPesoPotencia();

return
true;
}


//// implementacion de la funcionalidad (metodos privados)

//// relacionPesoPotencia()
private function relacionPesoPotencia()
{
if (
$this->potencia>0)
{
$this->relPesoPotencia = ($this->peso/$this->potencia);
}else
{
$this->relPesoPotencia = -1;
}
}


//// interfaz publica



//// dimeRelacionPesoPotencia()
public function dimeRelacionPesoPotencia()
{
$this->relacionPesoPotencia();
return
$this->relPesoPotencia;
}

//// muestraCaracteristicas()
public function muestraCaracteristicas()
{
echo
"Caracteristicas del vehiculo:<br><br>";
echo
"Potencia=".$this->potencia."<br>";
echo
"Peso=".$this->peso."<br>";
echo
"Peso/Potencia=".$this->relPesoPotencia."<br>";
echo
"Color1=".$this->color1."<br>";
echo
"Color2=".$this->color2."<br>";
echo
"Color3=".$this->color3."<br>";

return
true;
}

}

En esta nueva versión, existe un atributo $relPesoPotencia definido como privado. Y el cálculo de la relación peso potencia también se considera que forma parte de la implementación, no de la interfaz de comunicación, por lo que la función relacionPesoPotencia() también se declara privada. Para acceder a esta característica se implementa un método público (interfaz) llamado dimeRelacionPesoPotencia().

El constructor de 'Vehiculos' se encarga de calcular automáticamente la relación peso/potencia:

  //// constructor
function __construct($potencia,$peso)
{
$this->potencia = $potencia;
$this->peso = $peso;

//// calcula la relacion peso/potencia para este vehiculo
$this->relacionPesoPotencia();

return
true;
}

Ahora creamos una clase Moto, derivada de Vehiculo:

//// una moto 'es' un vehiculo
class Moto extends Vehiculo
{
//// atributos publicos
public $cilindrada;
public
$tipoMotor;

//// $color1 ya existe en la clase base y es publico
public $color1 = "verde";

//// atributos protegidos
//// $color2 ya existe en la clase base y es protegido
protected $color2 = "verde_oscuro";

//// atributos privados
//// $color3 ya existe en la clase base y es privado
private $color3 = "verde_claro";


//// constructor
function __construct($potencia,$peso)
{
//// lanzamos el constructor de la clase base
parent::__construct($potencia, $peso);
return
true;
}


//// muestraCaracteristicas()
//// sustituye la funcionalidad de la clase base
public function muestraCaracteristicas()
{
echo
"Caracteristicas de la moto:<br><br>";
echo
"Potencia=".$this->potencia."<br>";
echo
"Peso=".$this->peso."<br>";
echo
"Peso/Potencia (mal)=".$this->relPesoPotencia."<br>";
echo
"Peso/Potencia (bien)=".$this->dimeRelacionPesoPotencia()."<br>";
echo
"Color1=".$this->color1."<br>";
echo
"Color2=".$this->color2."<br>";
echo
"Color3=".$this->color3."<br>";

echo
"Cilindrada=".$this->cilindrada."<br>";
echo
"Tipo Motor=".$this->tipoMotor."<br>";

return
true;
}

public function
muestraCaracteristicasVehiculo()
{
Vehiculo::muestraCaracteristicas();
}


}
//// fin de la clase "Moto"



//// creamos un objeto Moto
$obj_moto = new Moto(60,190);
echo
$obj_moto->dimeRelacionPesoPotencia();

//// definimos algunas caracteristicas de esta moto
$obj_moto->cilindrada = 600;
$obj_moto->tipoMotor = "cuatro_tiempos";


//// mostramos las caracteristicas de la moto
$obj_moto->muestraCaracteristicas();

//// mostramos las caracteristicas del vehiculo
//// (una moto es un vehiculo)
$obj_moto->muestraCaracteristicasVehiculo();

El constructor de la clase Moto simplemente llama al constructor de la clase Vehiculo, puesto que en este caso no tiene que llevar a cabo ninguna inicialización adicional. La llamada al constructor de la clase base se puede hacer como Vehiculo::__construct(..), o de una forma más flexible como parent::__construct(..)

  //// constructor
function __construct($potencia,$peso)
{
//// lanzamos el constructor de la clase base
Vehiculo::__construct($potencia, $peso);
parent::__construct($potencia, $peso);
return
true;
}

Los metodos de las clases derivadas siempre sobrescriben (override) a los métodos de igual nombre de la clase base. Es decir los métodos definidos en la clase derivada sustituyen a los de la clase base a menos que se acceda explicitamente a través del operador de alcance '::'. Por ejemplo, la clase Moto ha redefinido la funcionalidad del método mostrarCaracteristicas() para adaptarla a sus necesidades concretas.

/// creamos un objeto Moto
$obj_moto = new Moto(60,190);
echo
$obj_moto->dimeRelacionPesoPotencia();

//// definimos algunas caracteristicas de esta moto
$obj_moto->cilindrada = 600;
$obj_moto->tipoMotor = "cuatro_tiempos";


//// mostramos las caracteristicas de la moto
$obj_moto->muestraCaracteristicas();

Obtendremos:

Caracteristicas de la moto:

Potencia=60
Peso=190
Peso/Potencia (mal)=
Peso/Potencia (bien)=3.1666666666667
Color1=verde
Color2=verde_oscuro
Color3=verde_claro
Cilindrada=600
Tipo Motor=cuatro_tiempos

En la implementación del método muestraCaracteristicas() de Moto se intenta acceder a un atributo privado ($this->relPesoPotencia) de la clase base Vehiculo. Como este atributo no es visible desde la clase derivada, PHP inicializa de forma automática una nueva variable llamada relPesoPotencia en el espacio de la clase Moto. Como es lógico, la variable se inicializa sin contenido.

Si ejecutamos el método muestraCaracteristicas() de la clase base:

//// mostramos las caracteristicas del vehiculo
//// (una moto es un vehiculo)
$obj_moto->muestraCaracteristicasVehiculo();

Obtendremos:

Caracteristicas del vehiculo:

Potencia=60
Peso=190
Peso/Potencia=3.1666666666667
Color1=verde
Color2=verde_oscuro
Color3=rojo_claro

Como regla práctica, en el caso de que exista coincidencia de nombre entre un atributo público (y protegido) de una clase y un atributo de su clase derivada, PHP considera que en realidad son la misma variable. En el ejemplo anterior, los atributos color1 (public) y color2 (protected) definidos en la clase base se han actualizado al redefinirlos en la clase derivada (pasan de ser rojos a ser verdes). En el caso de color3 (private en Vehiculo), existen dos versiones: la de la clase base y la de la clase derivada.

Si hacemos recuento de atributos 'color' en el objeto $obj_moto:

$color1
$color2
$color3 --Vehiculo--
$color3 --Moto--