Skip to content

Unidad 2.3: Sintaxis de objetos en PHP


Objetivo:

Introducir a los alumnos en la programación orientada a objetos (POO) con PHP, cubriendo la sintaxis básica y cómo trabajar con clases, objetos, propiedades y métodos.


1. Introducción a la Programación Orientada a Objetos (POO) en PHP

  • ¿Qué es la programación orientada a objetos?
  • Ventajas de la POO en el desarrollo web.
  • Explicación de los conceptos fundamentales:
    • Clase: Plantilla o molde para crear objetos.
    • Objeto: Instancia de una clase.
    • Propiedad: Variable dentro de una clase.
    • Método: Función dentro de una clase.

2. Sintaxis básica de objetos en PHP

2.1 Creación de una clase y un objeto

  • Definición de una clase:
Clase Persona
<?php 
class Persona {
    public $nombre;
    public $edad;

    public function saludar() {
        echo "Hola, soy $this->nombre y tengo $this->edad años.";
    }
}
?>
  • Instanciación de un objeto de una clase:
Instanciación de un objeto
1
2
3
4
5
6
<?php
$persona1 = new Persona();
$persona1->nombre = "Ana";
$persona1->edad = 25;
$persona1->saludar(); // Hola, soy Ana y tengo 25 años.
?>

2.2 Propiedades y métodos

  • Propiedades: Atributos de una clase que describen el objeto.
  • Métodos: Funciones definidas dentro de una clase.

Existen algunos métodos especiales en PHP que se llaman métodos mágicos. Estos métodos empiezan y terminan con dos guiones bajos __.

  • __construct(): Método constructor que se ejecuta al crear un objeto.
  • __destruct(): Método destructor que se ejecuta al destruir un objeto.
  • __toString(): Método para convertir un objeto a una cadena.

Un ejemplo de implmentación de un objeto con estos métodos mágicos sería:

Clase Persona
<?php
class Persona {
    public $nombre;
    public $edad;

    public function __construct($nombre, $edad) {
        $this->nombre = $nombre;
        $this->edad = $edad;
    }

    public function __destruct() {
        echo "El objeto ha sido destruido.";
    }

    public function __toString() {
        return "Nombre: $this->nombre, Edad: $this->edad";
    }
}
?>

Ejemplo de creación y uso de un objeto con métodos mágicos:

Uso de la clase Persona
1
2
3
4
5
6
7
8
<?php
$persona1 = new Persona("Juan", 30);
echo $persona1->nombre; // Juan
$persona1->edad = 35;
echo $persona1->edad; // 35
echo $persona1; // Nombre: Juan, Edad: 35
unset($persona1); // El objeto ha sido destruido.
?>

Clases abstractas e interfaces

  • Clases abstractas: Son clases que no pueden ser instanciadas directamente, sino que se utilizan como plantillas para otras clases.
  • Interfaces: Son como clases abstractas, pero solo contienen métodos sin implementación. Las clases que implementan una interfaz deben definir los métodos de la interfaz.

Para ello utilizaremos la palabra reservada abstract para las clases abstractas y interface para las interfaces. Las propiedades y métodos de una clase abstracta deben ser implementados en las clases que heredan de ella.

Clase abstracta y interfaz
<?php
abstract class Figura {
    abstract public function area();
    abstract public function perimetro();
}

interface Dibujable {
    public function dibujar();
}   

class Cuadrado extends Figura implements Dibujable {
    public $lado;

    public function __construct($lado) {
        $this->lado = $lado;
    }

    public function area() {
        return $this->lado * $this->lado;
    }

    public function perimetro() {
        return 4 * $this->lado;
    }

    public function dibujar() {
        echo "Dibujando un cuadrado.";
    }
}
?>

Ejemplo de uso de una clase abstracta e interfaz:

Uso de la clase abstracta y la interfaz
1
2
3
4
5
6
<?php
$cuadrado = new Cuadrado(5);
echo "Área del cuadrado: " . $cuadrado->area() . "<br>";
echo "Perímetro del cuadrado: " . $cuadrado->perimetro() . "<br>";
$cuadrado->dibujar(); // Dibujando un cuadrado.
?>

¿Cómo saber si un objeto implementa una interfaz?

Para verificar si un objeto implementa una interfaz, se puede utilizar la función instanceof.

Verificar si un objeto implementa una interfaz
1
2
3
4
5
6
7
8
<?php
$cuadrado = new Cuadrado(5);
if ($cuadrado instanceof Dibujable) {
    echo "El cuadrado es dibujable.";
} else {
    echo "El cuadrado no es dibujable.";
}
?>

Métodos y propiedades estáticas

  • Métodos estáticos: Son métodos que se pueden llamar sin necesidad de instanciar un objeto.
  • Propiedades estáticas: Son propiedades que pertenecen a la clase en lugar de a una instancia específica.
Métodos y propiedades estáticas
<?php
class Matematicas {
    public static function sumar($a, $b) {
        return $a + $b;
    }

    public static $pi = 3.1416;
}

echo Matematicas::sumar(5, 3); // 8
echo Matematicas::$pi; // 3.1416
?>

2.3 Modificadores de acceso: public, private, protected

  • public: La propiedad o método es accesible desde cualquier parte del código.
  • private: La propiedad o método solo es accesible dentro de la clase.
  • protected: La propiedad o método es accesible dentro de la clase y sus subclases.
Modificadores de acceso
<?php
class Empleado {
    public $nombre;
    private $salario;

    public function __construct($nombre, $salario) {
        $this->nombre = $nombre;
        $this->salario = $salario;
    }

    public function mostrarSalario() {
        echo "El salario de $this->nombre es $this->salario.";
    }
}

$empleado1 = new Empleado("Carlos", 3000);
$empleado1->mostrarSalario(); // El salario de Carlos es 3000.
?>

3. Herencia en PHP

3.1 ¿Qué es la herencia?

La herencia permite que una clase herede métodos y propiedades de otra clase. Esto ayuda a reutilizar el código y a mantener una estructura más organizada.

Ejemplo de herencia
<?php 
class Animal {
    public $nombre;

    public function __construct($nombre) {
        $this->nombre = $nombre;
    }

    public function hablar() {
        echo "$this->nombre hace un sonido.";
    }
}

class Perro extends Animal {
    public function hablar() {
        echo "$this->nombre dice: ¡Guau!";
    }
}

$miPerro = new Perro("Rex");
$miPerro->hablar(); // Rex dice: ¡Guau!
?>

3.2 Métodos y propiedades heredadas

  • Uso de parent:: para acceder a métodos y propiedades de la clase padre.
Uso de parent::
<?php
class Persona {
    public $nombre;

    public function __construct($nombre) {
        $this->nombre = $nombre;
    }

    public function saludar() {
        echo "Hola, soy $this->nombre.";
    }
}

class Empleado extends Persona {
    public function saludar() {
        parent::saludar();
        echo " Y soy un empleado.";
    }
}

$empleado = new Empleado("Juan");
$empleado->saludar(); // Hola, soy Juan. Y soy un empleado.
?>

4. Creación de módulos PHP y su reutilización

1. ¿Qué es un módulo en PHP?

En PHP, un módulo es un fragmento de código que contiene una funcionalidad específica que puede ser importada o incluida en otros archivos. Los módulos son ideales para separar responsabilidades y reutilizar código en múltiples partes de la aplicación.

2. ¿Cómo crear y utilizar un módulo PHP?

2.1 Crear un módulo PHP

Para crear un módulo en PHP, simplemente se debe escribir el código en un archivo PHP independiente. Este archivo puede contener funciones, clases o variables que luego podrán ser utilizadas en otros archivos.

Ejemplo de un módulo para operaciones matemáticas:

Módulo de operaciones
// archivo: operaciones.php
<?php
function sumar($a, $b) {
    return $a + $b;
}

function restar($a, $b) {
    return $a - $b;
}

function multiplicar($a, $b) {
    return $a * $b;
}

function dividir($a, $b) {
    if ($b == 0) {
        return "Error: División por cero";
    }
    return $a / $b;
}
?>

2.2 Importar un módulo en otro archivo

Para poder usar este módulo, necesitamos importarlo en el archivo donde vamos a utilizar las funciones que definimos. Para ello, usamos include, require, include_once o require_once.

  • include: Incluye el archivo y genera un aviso si no se encuentra.
  • require: Incluye el archivo y genera un error fatal si no se encuentra.
  • include_once y require_once son similares, pero aseguran que el archivo se incluya solo una vez.

Ejemplo de cómo importar y usar el módulo operaciones.php:

Uso del módulo de operaciones
// archivo: calculadora.php
<?php
// Importamos el módulo de operaciones
include 'operaciones.php';

$a = 10;
$b = 5;

echo "Suma: " . sumar($a, $b) . "<br>";
echo "Resta: " . restar($a, $b) . "<br>";
echo "Multiplicación: " . multiplicar($a, $b) . "<br>";
echo "División: " . dividir($a, $b) . "<br>";
?>

3. Buenas prácticas en la creación de módulos PHP

  • Usar nombres descriptivos para los archivos y funciones.
  • Dividir el código en módulos pequeños según funcionalidades (por ejemplo, conexion_bd.php, validaciones.php, funciones_usuarios.php).
  • Utilizar funciones o clases para hacer el código reutilizable y evitar la repetición.
  • Documentar los módulos y funciones para facilitar su uso en proyectos más grandes.

5. Ejercicios prácticos

Ejercicio 1: Crear una clase Coche

Enunciado: Crea una clase Coche con las propiedades marca y modelo, y un método detalles() que muestre los detalles del coche. Instancia un objeto de esa clase y muestra los detalles.

Solución
Clase Coche
<?php
class Coche {
    public $marca;
    public $modelo;

    public function __construct($marca, $modelo) {
        $this->marca = $marca;
        $this->modelo = $modelo;
    }

    public function detalles() {
        echo "Marca: $this->marca, Modelo: $this->modelo";
    }
}

$miCoche = new Coche("Ford", "Focus");
$miCoche->detalles(); // Marca: Ford, Modelo: Focus
?>

Ejercicio 2: Crear una clase CuentaBancaria

Enunciado: Crea una clase CuentaBancaria con las propiedades titular y saldo. La clase debe tener un método para ingresar dinero y otro para retirar. Crea una instancia de la clase, ingresa dinero, retíralo y muestra el saldo.

Solución
Clase CuentaBancaria
<?php
class CuentaBancaria {
    public $titular;
    public $saldo;

    public function __construct($titular, $saldo = 0) {
        $this->titular = $titular;
        $this->saldo = $saldo;
    }

    public function ingresar($cantidad) {
        $this->saldo += $cantidad;
    }

    public function retirar($cantidad) {
        $this->saldo -= $cantidad;
    }

    public function mostrarSaldo() {
        echo "Saldo de $this->titular: $this->saldo";
    }
}

$cuenta1 = new CuentaBancaria("Carlos", 1000);
$cuenta1->ingresar(500);
$cuenta1->retirar(200);
$cuenta1->mostrarSaldo(); // Saldo de Carlos: 1300
?>

Ejercicio 3: Herencia en PHP

Enunciado: Crea una clase base Animal con un método hacerSonido(). Luego, crea una clase Perro que herede de Animal y sobrescriba el método hacerSonido() para que diga "¡Guau!". Instancia un objeto de Perro y llama al método hacerSonido().

Solución
Herencia en PHP
<?php
class Animal {
    public function hacerSonido() {
        echo "El animal hace un sonido.";
    }
}

class Perro extends Animal {
    public function hacerSonido() {
        echo "¡Guau!";
    }
}

$miPerro = new Perro();
$miPerro->hacerSonido(); // ¡Guau!
?>

Ejercicio 4: Uso de parent:: para acceder a métodos de la clase padre

Enunciado: Crea una clase base Vehiculo con un método detalles(). Luego, crea una clase Coche que herede de Vehiculo y sobrescriba el método detalles() para agregar más información. Usa parent::detalles() para incluir la información de la clase padre.

Solución
<?php
class Vehiculo {
    public function detalles() {
        echo "Este es un vehículo.";
    }
}

class Coche extends Vehiculo {
    public function detalles() {
        parent::detalles();
        echo " Y es un coche.";
    }
}

$miCoche = new Coche();
$miCoche->detalles(); // Este es un vehículo. Y es un coche.
?>

Ejercicio 5: Clases y objetos en PHP

Vamos a crear una jerarquía de clase, para ello utilizaremos los conceptos de clases, objetos, herencia, interfaces y clases abstractas en PHP. Crearemos una serie de clases que representan figuras geométricas y que implementan una interfaz para poder ser dibujadas.

Matemáticamente el cálculo de sis dos figuras se solapan pude ser complicado, aquí tenéis un ejemplo de cómo se puede hacer. En caso de que no queráis hacerlo, podéis añadir a Dibujable los métodos Trasladar y Rotar, que permitan mover y rotar la figura. Para la rotación pasaremos como parámetro el ángulo en grados, se rotará desde el punto (0,0) y se devolverá la figura rotada.

Enunciado 1: Crear la clase Color

Crear la clase Color

Enunciado: Crea una clase Color con tres propiedades: rojo, verde y azul. Los valores de estas propiedades deben estar entre 0 y 255. Implementa un constructor que inicialice estas propiedades y un método __toString que devuelva el color en formato RGB(255, 100, 50).

Solución
Clase Color
<?php
class Color {
    public $rojo;
    public $verde;
    public $azul;

    public function __construct($rojo, $verde, $azul) {
        if ($this->validarColor($rojo) && $this->validarColor($verde) && $this->validarColor($azul)) {
            $this->rojo = $rojo;
            $this->verde = $verde;
            $this->azul = $azul;
        } else {
            echo "Error: los valores de color deben estar entre 0 y 255.";
        }
    }

    private function validarColor($valor) {
        return ($valor >= 0 && $valor <= 255);
    }

    public function __toString() {
        return "RGB($this->rojo, $this->verde, $this->azul)";
    }
}

$color1 = new Color(255, 100, 50);
echo $color1; // RGB(255, 100, 50)
?>

Enunciado 2: Crear la clase Punto

Crear la clase Punto

Enunciado: Crea una clase Punto con las propiedades x e y (entero) para poder ubicar un punto en un mapa 2D. Implementa un método distancia(Punto $punto) que calcule la distancia entre el punto actual y otro punto pasado como parámetro.

Solución
Clase Punto
<?php
class Punto {
    public $x;
    public $y;

    public function __construct($x, $y) {
        $this->x = $x;
        $this->y = $y;
    }

    // Método para calcular la distancia entre dos puntos
    public function distancia(Punto $punto) {
        return sqrt(pow($this->x - $punto->x, 2) + pow($this->y - $punto->y, 2));
    }
}

$punto1 = new Punto(0, 0);
$punto2 = new Punto(3, 4);

echo "Distancia entre los puntos: " . $punto1->distancia($punto2); // Distancia entre los puntos: 5
?>

Enunciado 3: Crear las interfaces Dibujable y Medible

Crear la interfaz Dibujable

Enunciado: Crea una interfaz Dibujable con un método abstracto dibujar() que debe devolver el array de puntos de la figura para que puedan ser dibujados, junto con el color de fondo y borde.

Solución
Interfaz Dibujable
1
2
3
4
5
6
7
8
9
<?php
interface Dibujable {
    public function dibujar();
}
interface Medible {
    public function area();
    public function perimetro();
}
?>

Enunciado 4: Crear la clase Figura (abstracta)

Crear la clase Figura (abstracta)

Enunciado: Crea una clase abstracta Figura con una propiedad privada que almacene un array de objetos Punto (los vértices de la figura), y propiedades protejidas para el color de fondo y el color del borde. Implementa métodos abstractos como area(), perimetro(), y solapar(Figura $figura) para verificar si la figura solapa con otra figura. El método solapar debe devolver true si alguna de las figuras se solapan. Para acceder a los colores, utiliza getters y setters.

Solución
Clase Figura
<?php
abstract class Figura implements Dibujable, Medible {
    private $vertices; // Array de puntos
    protected $colorBorde;
    protected $colorFondo;

    public function __construct($vertices, $colorBorde, $colorFondo) {
        $this->vertices = $vertices;
        $this->colorBorde = $colorBorde;
        $this->colorFondo = $colorFondo;
    }

    public function getVertices() {
        return $this->vertices;
    }

    public getColorBorde() {
        return $this->colorBorde;
    }

    public setColorBorde($colorBorde) {
        $this->colorBorde = $colorBorde;
    }

    public getColorFondo() {
        return $this->colorFondo;
    }

    public setColorFondo($colorFondo) {
        $this->colorFondo = $colorFondo;
    }

    abstract public function area();
    abstract public function perimetro();
    abstract public function solapar(Figura $figura);
}
?>

Enunciado 5: Crear la clase Cuadrado (heredando de Figura)

Crear la clase Cuadrado (heredando de Figura)

Enunciado: Crea la clase Cuadrado que herede de la clase Figura y que sobrescriba los métodos area(), perimetro() y solapar(Figura $figura). La clase Cuadrado tendrá un constructor que reciba los vértices, el color de borde, color de fondo. Tendrá un método dibujar() que devuelva los vértices y colores para poder dibujar el cuadrado.

Solución
Clase Cuadrado
<?php
class Cuadrado extends Figura implements Dibujable, Medible {

    public function __construct($puntos, $colorBorde, $colorFondo) {
        parent::__construct($puntos, $colorBorde, $colorFondo);
        $this->lado = $lado;
    }

    public function area() {
        $lado = $this->vertices[1]->distancia($this->vertices[0]);
        return pow($lado, 2);
    }

    public function perimetro() {
        $lado = $this->vertices[1]->distancia($this->vertices[0]);
        return 4 * $this->lado;
    }

    public function solapar(Figura $figura) {
        // Lógica de solapamiento
        return false;
    }

    public function dibujar() {
        return $this->getVertices() . $this->colorFondo . $this->colorBorde   ; // Devolver los vértices para dibujar
    }
}
?>

Enunciado 6: Crear la clase Círculo (heredando de Figura)

Crear la clase Círculo (heredando de Figura)

Enunciado: Crea la clase Círculo que herede de Figura y sobrescriba los métodos area(), perimetro() y solapar(Figura $figura). Para el caso especial del círculo (no tine vertices) utilizaremos el primer Punto como el centro del círculo y el segundo Punto como un punto en la circunferencia, de manera que el radio se calcula como la distancia entre estos dos puntos. La clase Círculo debe tener un constructor que reciba los puntos, el color de borde y color de fondo. Implementa el método dibujar() que devuelva los vértices y colores para poder dibujar el círculo.

Solución
Clase Círculo
<?php
class Circulo extends Figura implements Dibujable. Medible {
    private $radio;

    public function __construct($puntos, $colorBorde, $colorFondo, $radio) {
        parent::__construct($puntos, $colorBorde, $colorFondo);
        $this->radio = $radio;
    }

    public function area() {
        return pi() * $this->radio * $this->radio;
    }

    public function perimetro() {
        return 2 * pi() * $this->radio;
    }

    public function solapar(Figura $figura) {
        // Lógica de solapamiento
        return false;
    }

    public function dibujar() {
        return $this->getVertices(); // Devolver los vértices para dibujar
    }
}
?>

Enunciado 7: Crear la clase Rectángulo (heredando de Figura)

Crear la clase Rectángulo (heredando de Figura)

Enunciado: Crea la clase Rectángulo que herede de Figura y sobrescriba los métodos area(), perimetro() y solapar(Figura $figura). La base y el alto del rectángulo se pueden calcular a partir de los vértices. La clase Rectángulo debe tener un constructor que reciba los vértices, el color de borde y color de fondo. Implementa el método dibujar() que devuelva los vértices y colores para poder dibujar el rectángulo.

Solución
<?php
class Rectangulo extends Figura implements Dibujable, Medible {
    private $alto;
    private $ancho;
    public function __construct($puntos, $colorBorde, $colorFondo, $alto, $ancho) {
        parent::__construct($puntos, $colorBorde, $colorFondo);
        $this->alto = $alto;
        $this->ancho = $ancho;
      }

    public function area() {
        return $this->alto * $this->ancho;
    }

    public function perimetro() {
        return 2 * ($this->alto + $this->ancho);
    }

    public function solapar(Figura $figura) {
        // Lógica de solapamiento
        return false;
    }

    public function dibujar() {
        return $this->getVertices(); // Devolver los vértices para dibujar
    }
}
?>

Resumen

Con este ejercicio, los estudiantes habrán practicado:

  1. La creación de clases y objetos en PHP.
  2. Herencia y sobrescritura de métodos.
  3. Interfaces y clases abstractas.
  4. Cálculos geométricos con métodos de área y perímetro.
  5. Creación de figuras que implementan métodos abstractos y se pueden dibujar.

Ejercicio 6: Clases y objetos en PHP - Sistema de Vehículos

Vamos a crear una jerarquía de clases para representar diferentes tipos de vehículos. Usaremos los conceptos de clases, objetos, herencia, interfaces y clases abstractas en PHP.

Enunciado 1: Crear la clase Motor

Crear la clase Motor

Enunciado: Crea una clase Motor con propiedades potencia y tipoCombustible. Implementa un constructor que inicialice estas propiedades y un método __toString que devuelva la descripción del motor en el formato Motor: Potencia = 200 CV, Tipo de Combustible = Gasolina.

Solución
Clase Motor
<?php
class Motor {
    public $potencia;
    public $tipoCombustible;

    public function __construct($potencia, $tipoCombustible) {
        $this->potencia = $potencia;
        $this->tipoCombustible = $tipoCombustible;
    }

    public function __toString() {
        return "Motor: Potencia = $this->potencia CV, Tipo de Combustible = $this->tipoCombustible";
    }
}

$motor1 = new Motor(200, "Gasolina");
echo $motor1; // Motor: Potencia = 200 CV, Tipo de Combustible = Gasolina
?>

Enunciado 2: Crear la clase Vehiculo (abstracta)

Crear la clase Vehiculo (abstracta)

Enunciado: Crea una clase abstracta Vehiculo con propiedades comunes como marca, modelo, color, y un motor (objeto de la clase Motor). Implementa un método abstracto calcularConsumo() y un método mostrarDetalles() que devuelva la marca, el modelo, y el color del vehículo.

Solución
Clase Vehiculo
<?php
abstract class Vehiculo {
    protected $marca;
    protected $modelo;
    protected $color;
    protected $motor;

    public function __construct($marca, $modelo, $color, $motor) {
        $this->marca = $marca;
        $this->modelo = $modelo;
        $this->color = $color;
        $this->motor = $motor;
    }

    public function mostrarDetalles() {
        return "Marca: $this->marca, Modelo: $this->modelo, Color: $this->color";
    }

    abstract public function calcularConsumo();
}
?>

Enunciado 3: Crear la interfaz Mantenimiento

Crear la interfaz Mantenimiento

Enunciado: Crea una interfaz Mantenimiento con el método necesitaMantenimiento(), que devuelve true o false dependiendo de si el vehículo necesita mantenimiento.

Solución
Interfaz Mantenimiento
1
2
3
4
5
<?php
interface Mantenimiento {
    public function necesitaMantenimiento();
}
?>

Enunciado 4: Crear la clase Coche (heredando de Vehiculo y Mantenimiento)

Crear la clase Coche (heredando de Vehiculo y Mantenimiento)

Enunciado: Crea la clase Coche que herede de Vehiculo y que implemente la interfaz Mantenimiento. La clase debe tener una propiedad adicional numPuertas (número de puertas) y un método calcularConsumo() que calcule el consumo de combustible (por ejemplo, 8L/100 km). Además, implementa el método necesitaMantenimiento() que devuelva true si el coche ha recorrido más de 10,000 km.

Solución
Clase Coche
<?php
class Coche extends Vehiculo implements Mantenimiento {
    private $numPuertas;
    private $kilometros;

    public function __construct($marca, $modelo, $color, $motor, $numPuertas, $kilometros) {
        parent::__construct($marca, $modelo, $color, $motor);
        $this->numPuertas = $numPuertas;
        $this->kilometros = $kilometros;
    }

    public function calcularConsumo() {
        return 8; // 8L/100 km
    }

    public function necesitaMantenimiento() {
        return $this->kilometros > 10000;
    }
}

// Crear un motor
$motorCoche = new Motor(200, "Gasolina");

// Crear un coche
$coche = new Coche("Toyota", "Corolla", "Rojo", $motorCoche, 4, 12000);

echo $coche->mostrarDetalles(); // Marca: Toyota, Modelo: Corolla, Color: Rojo
echo "Consumo: " . $coche->calcularConsumo() . " L/100 km\n";
echo "¿Necesita mantenimiento? " . ($coche->necesitaMantenimiento() ? "Sí" : "No") . "\n";
?>

Enunciado 5: Crear la clase Camion (heredando de Vehiculo y Mantenimiento)

Crear la clase Camion (heredando de Vehiculo y Mantenimiento)

Enunciado: Crea la clase Camion que herede de Vehiculo y que implemente la interfaz Mantenimiento. La clase debe tener una propiedad adicional capacidadCarga (en kg). El método calcularConsumo() debe calcular el consumo de combustible dependiendo de la carga (por ejemplo, 15L/100 km por cada tonelada de carga). Además, implementa el método necesitaMantenimiento() que devuelva true si el camión ha recorrido más de 20,000 km.

Solución
Clase Camion
<?php
class Camion extends Vehiculo implements Mantenimiento {
    private $capacidadCarga;
    private $kilometros;

    public function __construct($marca, $modelo, $color, $motor, $capacidadCarga, $kilometros) {
        parent::__construct($marca, $modelo, $color, $motor);
        $this->capacidadCarga = $capacidadCarga;
        $this->kilometros = $kilometros;
    }

    public function calcularConsumo() {
        return 15 * ($this->capacidadCarga / 1000); // Consumo depende de la carga
    }

    public function necesitaMantenimiento() {
        return $this->kilometros > 20000;
    }
}

// Crear un motor para el camión
$motorCamion = new Motor(400, "Diesel");

// Crear un camión
$camion = new Camion("Volvo", "FH", "Azul", $motorCamion, 10000, 25000);

echo $camion->mostrarDetalles(); // Marca: Volvo, Modelo: FH, Color: Azul
echo "Consumo: " . $camion->calcularConsumo() . " L/100 km\n";
echo "¿Necesita mantenimiento? " . ($camion->necesitaMantenimiento() ? "Sí" : "No") . "\n";
?>

Resumen

Con este ejercicio, los estudiantes habrán practicado:

  1. La creación de clases y objetos en PHP.
  2. Herencia entre clases como Vehiculo, Coche, y Camion.
  3. Interfaces como Mantenimiento para aplicar comportamientos comunes.
  4. Métodos abstractos en la clase Vehiculo como calcularConsumo() que deben ser implementados en las clases hijas.
  5. Comparar el consumo de vehículos y determinar si necesitan mantenimiento.

Ejercicio 6: Sistema de Vehículos con Repostajes y Mantenimientos Específicos

En este ejercicio, vamos a desarrollar un sistema de gestión para diferentes tipos de vehículos, como coches, motos y camiones. El sistema permitirá registrar repostajes, realizar cálculos sobre el consumo de combustible, y gestionar los mantenimientos necesarios en función de los kilómetros recorridos por cada vehículo.

Cada tipo de vehículo tendrá un conjunto de mantenimientos específicos predefinidos, que se agregarán automáticamente al crear una instancia de cada vehículo. Además, los vehículos podrán gestionar sus repostajes, actualizar los kilómetros recorridos, y calcular el consumo total o consumo actual basado en los últimos n repostajes.

Objetivos del ejercicio:

  • Gestionar repostajes: Cada repostaje tiene asociados los kilómetros recorridos y los litros de combustible añadidos.
  • Calcular el consumo: Se calculará el consumo total de combustible y el consumo basado en los últimos n repostajes.
  • Gestionar mantenimientos: Cada vehículo tendrá una lista de mantenimientos específicos, que deberán realizarse en momentos específicos basados en los kilómetros recorridos.
  • Actualizar los mantenimientos pendientes: Cuando se realice un repostaje, se verificará si hay mantenimientos pendientes en función de los kilómetros recorridos y se actualizarán automáticamente.

Esquema del ejercicio:

  1. Crear la clase Repostaje: Definir las propiedades kilometros y litros.
  2. Crear la clase Mantenimiento: Definir las propiedades kilometros y tipo para cada tipo de mantenimiento.
  3. Crear la clase abstracta Vehiculo: Esta clase base tendrá propiedades comunes como marca, modelo, color, y métodos para añadir repostajes, gestionar mantenimientos y calcular consumos.
  4. Crear clases específicas (Coche, Moto, Camion): Estas clases implementarán los mantenimientos específicos de cada tipo de vehículo y cargarán estos mantenimientos al crear el vehículo.
  5. Gestionar mantenimientos: Al realizar un repostaje, el sistema verificará si hay mantenimientos pendientes en los próximos 10,000 km y los añadirá automáticamente a la lista de mantenimientos pendientes.

Este ejercicio te permitirá practicar el uso de herencia, métodos abstractos, interfaces y gestión de datos con arrays en PHP, todo ello en el contexto de un sistema realista de gestión de vehículos.

Enunciado 1: Crear la clase Repostaje

Crear la clase Repostaje

Enunciado: Vamos a crear la clase Repostaje, que representará un repostaje de combustible en el vehículo. Esta clase debe tener las propiedades kilometros (que indicará los kilómetros recorridos en el momento del repostaje) y litros (que indicará los litros de combustible añadidos).

Solución
Clase Repostaje
<?php
class Repostaje {
    public $kilometros;
    public $litros;

    public function __construct($kilometros, $litros) {
        $this->kilometros = $kilometros;
        $this->litros = $litros;
    }
}
?>

Enunciado 2: Crear la clase Mantenimiento

Crear la clase Mantenimiento

Enunciado: Ahora crearemos la clase Mantenimiento, que representará un mantenimiento que debe realizarse en el vehículo. Esta clase debe tener dos propiedades: kilometros (que indica los kilómetros en los que debe realizarse el mantenimiento) y tipo (que describe el tipo de mantenimiento, como "Cambio de aceite", "Revisión de frenos", etc.).

Solución
Clase Mantenimiento
<?php
class Mantenimiento {
    public $kilometros;
    public $tipo;

    public function __construct($kilometros, $tipo) {
        $this->kilometros = $kilometros;
        $this->tipo = $tipo;
    }
}
?>

Enunciado 3: Crear la clase abstracta Vehiculo

Crear la clase abstracta Vehiculo

Enunciado: Ahora vamos a crear la clase abstracta Vehiculo, que será la clase base para los diferentes tipos de vehículos (Coche, Moto, Camión). Esta clase debe contener las propiedades comunes para todos los vehículos como marca, modelo, color, motor, y kilometros. Además, debe tener métodos para añadir repostajes, consultar los repostajes realizados, y calcular el consumo total y actual. Implementaremos también un método gestionarMantenimientos para verificar si hay mantenimientos pendientes.

La clase Vehiculo debe incluir un método abstracto llamado cargarMantenimientos(), que será implementado en las clases hijas para cargar los mantenimientos específicos.

Solución
Clase Vehiculo
<?php
abstract class Vehiculo {
    protected $marca;
    protected $modelo;
    protected $color;
    protected $motor;
    protected $kilometros = 0; // Kilómetros iniciales
    protected $repostajes = [];
    protected $mantenimientos = [];
    protected $pendientes = [];

    public function __construct($marca, $modelo, $color, $motor) {
        $this->marca = $marca;
        $this->modelo = $modelo;
        $this->color = $color;
        $this->motor = $motor;
        $this->cargarMantenimientos(); // Cargar los mantenimientos específicos al crear el vehículo
    }

    // Método abstracto para cargar mantenimientos específicos
    abstract protected function cargarMantenimientos();

    // Método para añadir repostaje
    public function añadirRepostaje($repostaje) {
        $this->repostajes[] = $repostaje;
        $this->kilometros = $repostaje->kilometros; // Actualizamos los kilómetros del vehículo
        $this->gestionarMantenimientos($repostaje);
    }

    // Método para gestionar los mantenimientos pendientes
    public function gestionarMantenimientos($repostaje) {
        foreach ($this->mantenimientos as $mantenimiento) {
            if ($mantenimiento->kilometros <= $repostaje->kilometros + 10000) {
                $this->pendientes[] = $mantenimiento;
            }
        }
    }

    // Calcular consumo total
    public function calcularConsumoTotal() {
        $totalKm = 0;
        $totalLitros = 0;
        foreach ($this->repostajes as $repostaje) {
            $totalKm += $repostaje->kilometros;
            $totalLitros += $repostaje->litros;
        }
        return $totalLitros / $totalKm;
    }

    // Calcular consumo de los últimos 'n' repostajes
    public function calcularConsumoActual($n) {
        $totalKm = 0;
        $totalLitros = 0;
        $count = 0;
        for ($i = count($this->repostajes) - 1; $i >= 0 && $count < $n; $i--) {
            $repostaje = $this->repostajes[$i];
            $totalKm += $repostaje->kilometros;
            $totalLitros += $repostaje->litros;
            $count++;
        }
        return $totalLitros / $totalKm;
    }

    // Consultar repostajes
    public function consultarRepostajes() {
        return $this->repostajes;
    }

    // Consultar mantenimientos pendientes
    public function consultarMantenimientosPendientes() {
        return $this->pendientes;
    }

    // Registrar un mantenimiento realizado
    public function mantenimientoRealizado($mantenimiento) {
        $this->kilometros += $mantenimiento->kilometros;
        $this->gestionarMantenimientos($mantenimiento);
    }
}
?>

Enunciado 4: Crear la clase Coche (heredando de Vehiculo)

Crear la clase Coche (heredando de Vehiculo)

Enunciado: Vamos a crear la clase Coche, que hereda de Vehiculo y que implementará el método abstracto cargarMantenimientos(). En el constructor de esta clase se cargarán los mantenimientos específicos para el coche (por ejemplo, cambio de aceite cada 10,000 km, revisión de frenos cada 20,000 km, etc.).

Solución
Clase Coche
<?php
class Coche extends Vehiculo {
    protected function cargarMantenimientos() {
        // Cargar los mantenimientos específicos para el coche
        $this->mantenimientos = [
            new Mantenimiento(10000, "Cambio de aceite"),
            new Mantenimiento(20000, "Revisión de frenos"),
            new Mantenimiento(30000, "Revisión general")
        ];
    }
}
?>

Enunciado 5: Crear la clase Moto (heredando de Vehiculo)

Crear la clase Moto (heredando de Vehiculo)

Enunciado: Ahora vamos a crear la clase Moto, que también hereda de Vehiculo e implementa el método cargarMantenimientos(). Los mantenimientos específicos para la moto (por ejemplo, cambio de aceite cada 5,000 km, revisión de frenos cada 15,000 km) se cargarán automáticamente al crear una instancia de la clase Moto.

Solución
Clase Moto
<?php
class Moto extends Vehiculo {
    protected function cargarMantenimientos() {
        // Cargar los mantenimientos específicos para la moto
        $this->mantenimientos = [
            new Mantenimiento(5000, "Cambio de aceite"),
            new Mantenimiento(15000, "Revisión de frenos")
        ];
    }
}
?>

Enunciado 6: Crear la clase Camion (heredando de Vehiculo)

Crear la clase Camion (heredando de Vehiculo)

Enunciado: Finalmente, vamos a crear la clase Camion, que también hereda de Vehiculo e implementa el método cargarMantenimientos(). Los mantenimientos específicos para el camión (por ejemplo, cambio de aceite cada 20,000 km, revisión de frenos cada 40,000 km) se cargarán automáticamente.

Solución
Clase Camion
<?php
class Camion extends Vehiculo {
    protected function cargarMantenimientos() {
        // Cargar los mantenimientos específicos para el camión
        $this->mantenimientos = [
            new Mantenimiento(20000, "Cambio de aceite"),
            new Mantenimiento(40000, "Revisión de frenos"),
            new Mantenimiento(50000, "Inspección de motor")
        ];
    }
}
?>

Ejemplo de uso del código:

Ejmeplo de uso

Enunciado: A continuación, se muestra un ejemplo de cómo utilizar las clases creadas para gestionar un coche, incluyendo repostajes y mantenimientos.

Solución
Ejemplo de uso
<?php
// Crear el motor
$motor = new Motor(150, "Gasolina");

// Crear un coche
$coche = new Coche("Ford", "Focus", "Rojo", $motor);

// Crear y añadir repostajes
$repostaje1 = new Repostaje(1000, 50);
$repostaje2 = new Repostaje(2000, 55);
$coche->añadirRepostaje($repostaje1);
$coche->añadirRepostaje($repostaje2);

// Consultar y gestionar mantenimientos pendientes
$coche->mantenimientoRealizado(new Mantenimiento(10000, "Cambio de aceite"));
$coche->mantenimientoRealizado(new Mantenimiento(20000, "Revisión de frenos"));

// Consultar repostajes y mantenimientos pendientes
echo "Kilómetros actuales del coche: " . $coche->kilometros . "\n";
echo "Mantenimientos pendientes: \n";
print_r($coche->consultarMantenimientosPendientes());
?>

Resumen

Con este ejercicio, los estudiantes habrán aprendido a:

  1. Crear clases abstractas y heredar de ellas en PHP.
  2. Gestionar repostajes y cálculos de consumo de combustible en función de los repostajes realizados.
  3. Añadir mantenimientos específicos para cada tipo de vehículo y gestionarlos en función de los kilómetros recorridos.
  4. Actualizar automáticamente los mantenimientos pendientes a medida que se realizan repostajes y se actualizan los kilómetros del vehículo.