Una de las ventajas que nos da la programación orientada a objetos es, por un lado, la forma ordenada de escribir código, y por otro la reutilizacion del mismo.
Supongamos que tenemos una clase basada en un auto:
<?php
class Auto {
private $motor_encendido = false;
private $cantidad_de_puertas;
private $cantidad_de_ruedas;
private $marca;
public function __construct($cantidad_de_puertas, $cantidad_de_ruedas, $marca) {
$this->cantidad_de_puertas = $cantidad_de_puertas;
$this->cantidad_de_ruedas = $cantidad_de_ruedas;
$this->marca = $marca;
}
public function encenderMotor(){
$this->motor_encendido = true;
}
public function apagarMotor(){
$this->motor_encendido = false;
}
//Verifica si el motor está encendido para saber si el auto puede arrancar o no.
public function arrancar(){
return $this->motor_encendido;
}
}
?>
Una clase común como las que venimos haciendo. Con cuatro propiedades que definen si el motor está encendido, la cantidad de puertas, la cantidad de ruedas y la marca del auto. En el constructor definimos las propiedades excepto si el motor está encendido o apagado, y tres métodos: uno para encender el motor, otro para apagarlo y por último un método para arrancar el auto que devuelve si el motor está apagado o encendido.
Ahora supongamos que tenemos una clase para definir el prototipo de una moto. Sería más o menos así:
<?php
class Moto {
private $motor_encendido = false;
private $cantidad_de_ruedas;
private $marca;
public function __construct($cantidad_de_ruedas, $marca) {
$this->cantidad_de_ruedas = $cantidad_de_ruedas;
$this->marca = $marca;
}
public function encenderMotor(){
$this->motor_encendido = true;
}
public function apagarMotor(){
$this->motor_encendido = false;
}
//Verifica si el motor está encendido para saber si la moto puede arrancar o no.
public function arrancar(){
return $this->motor_encendido;
}
}
?>
La clase Moto es prácticamente idéntica a la clase Auto, sólo que con una mínima diferencia: la clase Moto no tiene una propiedad $cantidad_de_puertas, porque sencillamente una moto no tiene puertas.
Ahora, ¿por qué estás clases son tan parecidas? Si lo pensamos como personas y no como programadores (ésa es una de las cosas que nos permite la programación orientada a objetos) ¿Qué tienen en común un auto y una moto? Que ambos son vehículos.
Así que entonces podríamos tener una clase Vehiculo también:
<?php
class Vehiculo {
protected $motor_encendido = false;
protected $cantidad_de_puertas;
protected $cantidad_de_ruedas;
protected $marca;
protected function __construct($cantidad_de_puertas, $cantidad_de_ruedas, $marca) {
$this->cantidad_de_puertas = $cantidad_de_puertas;
$this->cantidad_de_ruedas = $cantidad_de_ruedas;
$this->marca = $marca;
}
public function encenderMotor(){
$this->motor_encendido = true;
}
public function apagarMotor(){
$this->motor_encendido = false;
}
//Verifica si el motor está encendido para saber si el auto puede arrancar o no.
public function arrancar(){
return $this->motor_encendido;
}
}
?>
Y ahora volveremos a crear nuestras clases Auto y Moto, pero heredando de esta última clase así:
<?php
//Ante de definir la clase incluimos la clase padre Vehiculo.
require_once 'Vehiculo.php';
class Auto extends Vehiculo {
public function __construct($cantidad_de_puertas, $cantidad_de_ruedas, $marca) {
parent::__construct($cantidad_de_puertas, $cantidad_de_ruedas, $marca);
}
}
?>
<?php
//Ante de definir la clase incluimos la clase padre Vehiculo.
require_once 'Vehiculo.php';
class Moto extends Vehiculo {
public function __construct($cantidad_de_ruedas, $marca) {
parent::__construct(0, $cantidad_de_ruedas, $marca);
}
}
?>
Como ven ambas clases ahora tienen mucho menos código. Ahora vamos a lo importante que permite la herencia:
La herencia permite que clases como Auto y Moto hereden de una clase madre, en nuestro caso la clase Vehiculo. ¿Y qué es lo que heredan? Las clases hijas heredan de las clases madres todas las propiedades y métodos, lo que permite ahorrar líneas de código innecesarias.
Ahora varios puntos para repasar.
Primero, dentro las clases hijas debe incluirse con require_once, u otra función de PHP para importar archivos el .php donde se encuentra la clase madre. Además cuando definimos la clase debemos utilizar la palabra reservada extends más el nombre de la clase padre:
class ClaseHija extends ClasePadre {}
Pueden verlo como lo definimos tanto en la clase Auto, como en Moto.
Otra cosa que también es interesante es que si bien una clase hija hereda los métodos de su clase madre también se pueden sobrescribir.
Por ejemplo en la clase Vehiculo nosotros tenemos un constructor cómo este:
protected function __construct($cantidad_de_puertas, $cantidad_de_ruedas, $marca) {
$this->cantidad_de_puertas = $cantidad_de_puertas;
$this->cantidad_de_ruedas = $cantidad_de_ruedas;
$this->marca = $marca;
}
Pero en la clase Moto lo que hacemos es sobrescribir el método constructor de la clase madre:
public function __construct($cantidad_de_ruedas, $marca) {
parent::__construct(0, $cantidad_de_ruedas, $marca);
}
Osea lo único que estamos haciendo es que cuando creemos un objeto basado en Moto el constructor cambie y omita el parámetro de $cantidad_de_puertas, que tomo esa propiedad como 0, ya que una moto no tiene puertas.
Además para llamar a métodos de una clase hija a una clase madre no lo hacemos con $this->metodo(), sino con parent::metodo(). En el caso de las propiedades sí se llaman con $this->propiedad.
Y por último, fijate que en la clase madre no usamos private para las propiedades sino que usamos otra palabra reservada, protected.
Repasemos, public era para que las propiedades y métodos se puedan acceder desde la clase y el objeto, mientras que private era sólo para que se acceda desde la clase. En el caso de protected es un intermedio, las propiedades y métodos no podrán accederse desde el objeto, pero sí se podrán acceder desde las clases y las clases que hereden esos métodos. Si yo le pusiera private a las propiedades de la clase Vehiculo, la clase Auto y Moto no podrían acceder a las mismas.
Acá les dejo un ejemplo de cómo serían los objetos basados en ambas clases:
objeto Auto:
<?php
require_once 'clases/Auto.php';
$auto = new Auto(4, 4, 'Ford');
$auto->encenderMotor();
if($auto->arrancar()){
echo 'El auto esta andando';
}else{
echo 'No se puede arrancar el auto si el motor no esta encendido';
}
?>
objeto Moto:
<?php
require_once 'clases/Moto.php';
$moto = new Moto(2, 'Yamaha');
$moto->encenderMotor();
if($moto->arrancar()){
echo 'La moto esta andando';
}else{
echo 'No se puede arrancar la moto si el motor no esta encendido';
}
?>
Saludos!
Anterior: Php orientado a objetos, parte 5: Constantes
Siguiente: Php orientado a objetos, parte 7: Clases abstractas y finales

cual es el alcance de la herencia, es decir hasta que nivel de sucecion se heredan los métodos
Sinceramente no sé si tiene un límite. Por lo que yo he visto en proyectos grandes, normalmente escritos con Frameworks, no tiene límites. Podés tener una clase A, otra B que hereda de A, C que hereda de B y D que hereda de C, y D va a heredar todas las propiedades y métodos de A, de B y de C. Obviamente cómo aclaro en el ejemplo siguiente: clases-abstractas-y-finales siempre y cuando una clase no sea final. Si la clase es por ejemplo
final class AlgunaClase {
}
Entonces ésta última no va a permitir que otra clase herede de sí misma.
Saludos!
Este tema si se me hizo un poco complicado, siento que falto un ejemplo mas claro para los que nos cuesta entender, aun asi gracias por el aporte es muy bueno, me quedo con dudas sobre este tema. ojala pudieras darnos un ejemplo mas claro. Gracias y saludos.
Fer me podrias ayudar con un ejemplo mas claro, para entender este tema, uno que sea para completo novato y que se expplique asi como explicas tus temas, ya que este lo que no entendi fue el ejemplo, Gracias Fer tr lo voy a agradecer mucho. saludos
Marco, el tema es muy sencillo. Suponete que vos tenés dos clases, clase A y clase B.
class A {
public function hacerAlgo(){
}
}
class B extends A {
}
La clase B hereda de la clase A, eso significa que va a heredar sus propiedades y métodos. El método hacerAlgo() le pertenece a la clase A, pero como B hereda de A, entonces desde la clase B también se va a invocar a las propiedades y métodos que tiene A. Osea que yo voy a poder hacer esto:
$a = new A();
$a->hacerAlgo();
Porque obviamente tengo un objeto de la clase A, y esa clase A tiene un método llamado hacerAlgo().
Pero también puedo hacer esto:
$b = new B();
$b->hacerAlgo();
Porque como B hereda de A, también podrá acceder a los métodos del padre.
Lo importante es que entiendas eso.
Más adelante vas a ver otro ejemplo de herencia cuando veas PDO.
Saludos!
Disculpa si doy molestias Fer, pero me cuesta aprender por eso soy muy pregunton y doy muchas molestias. Tengo otra duda, espero no te moleste, pero me podrias explicar esta parte.
public function __construct($cantidad_de_ruedas, $marca) {
parent::__construct(0, $cantidad_de_ruedas, $marca);
Debido a tu blog me anime a crear uno, y voy a poner un link hacia esta pagina yaque me parecio muy buena. Gracias por tu ayuda y te felicito nuevamente por tomarte el tiempo para ayudarnos a los novatos.
Marco, primero que nada, no molestas. Si no quisiera responder preguntas, hubiese cerrado los comentarios. Está bien que preguntes, nadie nació sabiendo, y todos vamos a aprendiendo cosas día a día, si no sabés, preguntá.
Con respecto a tu consulta, eso que mencionás se llama sobrescribir métodos.
Osea una clase hija hereda de una clase madre, hereda sus propiedades y métodos, osea esa clase hija va a contar con un método que tendrá el mismo comportamiento que la clase madre.
La clase Vehículo en su método constructor nos pide agregar tres parámetros: La cantidad de puertas, la cantidad de ruedas y la marca. Lo mismo pasa con la clase Auto que herda de Vehículo. Pero en el caso de Moto, no tiene sentido que tenga un método constructor con un parámetro puerta, porque la moto sencillamente no tiene puertas, lo cual nos obligaría a que cada vez que creamos un objeto de tipo Moto, el valor de $cantidad_de_puertas sea siempre 0. Para evitar la redundancia, creamos un constructor que va a sobrescribir, reemplazar, el método constructor que viene en Vehículo, que hará lo mismo, sólo que no nos pedirá que definamos la cantidad de puertas, sino que por defecto ese valor será 0.
Saludos!
confirmado ya me quedo claro el ejemplo de lo que comentaste Fer. Te anexo un ejemplo.
Pruebas
valor1=$v;
}
public function cargar2($v)
{
$this->valor2=$v;
}
public function imprimirResultado()
{
echo $this->resultado.»;
}
}
class Suma extends Operacion{
public function operar()
{
$this->resultado=$this->valor1+$this->valor2;
}
}
class Resta extends Operacion{
public function operar()
{
$this->resultado=$this->valor1-$this->valor2;
}
}
$suma=new Suma();
$suma->cargar1(10);
$suma->cargar2(10);
$suma->operar();
echo ‘El resultado de la suma de 10+10 es:’;
$suma->imprimirResultado();
$resta=new Resta();
$resta->cargar1(10);
$resta->cargar2(5);
$resta->operar();
echo ‘El resultado de la diferencia de 10-5 es:’;
$resta->imprimirResultado();
?>
Perfecto, Marco. Ésa es la idea. La herencia se da cuando exista una relación de «Es un». Un Perro hereda de (Es un) Animal, un Caniche hereda de (Es un) Perro. Como en tu ejemplo una Suma hereda de (Es un) Operación.
Saludos!
Te felicito por todo el trabajo que haz hecho. Muy claro todo el tutorial.
una consulta: la funcion arrancar() no se podria, para que quede mas claro, llamar get_motor_encendido() ?
Siguiendo con lo explicado en el capitulo 5 anterior
Me confunde un poco la condicion if arrancar() … un comentario nomas
Como estás dentro de la clase podés acceder a motor motor_encendido.
Los atributos privados se pueden acceder desde la clase, y sólo desde la clase.
Saludos!