Introducción a los objetos en PHP

Los objetos son estructuras que permiten encapsular y agrupar datos y su comportamiento, ocultando
los detalles mas complejos y solo exponiendo los detalles necesarios, promoviendo la abstracción y
la modularidad

Introducción a los objetos en PHP

La principal forma de definir objetos en PHP es mediante unas estructuras especiales llamadas clases.

Las clases son los planos donde se detallan las características de los objetos, y
con solo definir una unica clase se pueden generar muchos objetos, por lo que son muy útiles para
reutilizar código.

Generar objetos a partir de clases se conoce como instanciar y para llevarlo a cabo
se usa la palabra clave de PHP new

class NombreDeLaClase{
}
$object = new NombreDeLaClase;

Para entender como es que esto funciona tenemos que ilustrarlo con código que resuelva problemas
reales.

Pensemos por ejemplo en un producto de una tienda en línea, este producto debería contar con los
siguientes datos:

  • Titulo
  • Precio
  • Existencias
  • Descripción

Creemos una clase que represente esto:

class Product
{
    private string $title = 'Pasta dental';
    private string $description = 'Producto de higiene bucal';
    private float $price = 39.9;
    private int $stock = 4;
}

$Product = new Product;

Ahora tenemos una clase producto que agrupa y oculta sus datos, simplemente definimos una variable
para cada dato requerido y declaramos el tipo de dato.

Antes de cada variable usamos la palabra private que es el indicativo de que el dato
debe estar oculto y asi evitar que pueda ser accedido desde el exterior del objeto.

Podríamos haber definido un arreglo asociativo con estos datos, pero ¿como evitas que los datos sean
modificados por tus algoritmos o por otros módulos?, ó ¿como evitas que los valores que sí van a ser
modificados no se corrompan?

En el caso de un producto de una plataforma de comercio, el titulo y la descripción son valores que
no suelen cambiar durante la ejecución del programa.

Por otro lado el precio es un valor que podría variar si se aplican impuestos o descuentos pero tanto
el precio como las existencias son valores que de ser modificados tendrían que seguir algún criterio
(como el de nunca poder ser valores negativos por ejemplo).

Para resolver estas cuestiones crearemos las funciones que definirán el comportamiento interno del
producto, pero antes necesitamos aclarar ciertos detalles técnicos.

Propiedades, Métodos y su Visibilidad/Ocultamiento

Las propiedades de un objeto es como se conoce a las variables que definimos dentro de una clase para
contener los valores principales de un objeto.

Los métodos de una objeto son las funciones que definiremos dentro de una clase para programar el
comportamiento de dichos objetos y se declaran usando el formato que ya vimos para declarar funciones en PHP.

En conjunto las propiedades y métodos de un objeto es lo que se conoce como miembros de un objeto.

Y para controlar el nivel de ocultamiento de los miembros de un objeto se usan los modificadores de
visibilidad Public y Private y con ellos se controla que puede o
no ser accedido desde fuera del objeto.

Lo mas recomendable es por defecto definir todos los miembros como ocultos y solo definir como
visibles desde el exterior a ciertos miembros en particular.

Estos miembros accesibles desde el exterior representan la interfaz del objeto (la superficie de
contacto), y son el medio que usarán otros objetos y el resto del software para interactuar con
ellos.

Encapsulamiento

Los miembros de un objeto están aislados del resto de cosas del programa, pero no están aislados
entre si, ya que forman parte de la misma unidad estos pueden interactuar entre sí.

A esta característica de los objetos de permitir que sus elementos internos puedan referenciarse
entre ellos se le llama encapsulamiento.

Para poder hacer referencia a las propiedades o métodos de un objeto desde dentro del mismo se usa
una pseudovariable llamada $this, la cual es un comodín que hace referencia al
propio objeto.

Este comodín se usa en conjunto con el operador de objeto ->
(Operador flecha simple, el cual se construye con un «guión medio» y el símbolo «mayor que») para
realizar esta interacción entre los miembros de un objeto $this->.

Acceso a las Propiedades del objeto vía Getters

Los Getters son funciones pensados para permitir la lectura de los valores internos de un objeto de
forma controlada, se suelen llamar con el nombre de la propiedad que se desea leer pero precedida
por el prefijo get, por ejemplo getTitle(), getPrice(), getStock(), etc.

Poniendo en practica lo aprendido

Vamos a modificar el código de la clase producto y añadiremos los mecanismos para poder leer los
datos internos del producto
y al final del código vamos a llamarlos para comprobar que realmente estamos accediendo a la
información correcta.

class Product
{
    private string $title = 'Pasta dental';
    private string $description = 'Producto de higiene bucal';
    private float $price = 39.9;
    private int $stock = 4;

    public function getTitle()
    {
        return $this->title;
    }

    public function getDescription()
    {
        return $this->description;
    }

    public function getPrice()
    {
        return $this->price;
    }

    public function getStock()
    {
        return $this->stock;
    }
}

$Product = new Product;
echo '<div>
    <h4>'.$Product->getTitle().'</h4>
    <p>'.$Product->getDescription().'</p>
    <p>Precio: $'.$Product->getPrice().'</p>
    <p>Existencias: '.$Product->getStock().'</p>
</div>';

Este código PHP generará el siguiente código HTML:

<div>
    <h4>Pasta dental</h4>
    <p>Producto de higiene bucal</p>
    <p>Precio: $39.9</p>
    <p>Existencias: 4</p>
</div>

El cual se verá de la siguiente manera en el navegador:

Pasta dental

Producto de higiene bucal

Precio: $39.9

Existencias: 4

Hemos definido una función getter para cada propiedad de nuestro objeto y hemos dejado estos métodos
como públicos para permitir su acceso fuera del objeto.

Dentro de cada getter usamos la referencia al objeto contenedor y el operador flecha
$this-> para poder acceder a cada una de las propiedades.

Con todo esto logramos encapsular los datos de un producto de forma que no haya forma de modificar
sus valores, solo tenemos mecanismos para poder leer dichos datos.

Usando solo arreglos, constantes y funciones podemos emular todos estos comportamientos y conceptos,
pero definitivamente no es sencillo, y el código resultante no sería tan compacto como el que nos
permite generar la Programación Orientada a Objetos.

Aunque un problema del código que llevamos escrito hasta aquí es que solo esta definido para un único
producto, pero otra de las razones por las que usamos POO es por la facilidad que nos da para
reutilizar código, por lo que ahora veremos como generar multiples objetos con el mismo código.

Constructores de objetos

Dentro de cada clase podemos definir un método especial conocido como constructor, y este nos permite
proporcionarle a la clase los valores base con los que se creara cada objeto.

Este método especial no puede tener cualquier nombre, en concreto en PHP debe ser una función con el
nombre __construct y solo puede llevar el modificador de visibilidad
public.

A nuestro constructor podemos definirle argumentos de función como a cualquier otra función
convencional

Al estar dicho método especial encapsulado en una clase, podemos interactuar con el resto de miembros
del objeto, por lo que tomaremos los argumentos de la función y directamente los asignaremos a
propiedades del objeto.

De esta forma podemos usar la misma clase para crear multiples objetos con valores diferentes pero
reutilizando el mismo plano, permitiendo de forma elegante reutilizar grandes cantidades de código
para crear estructuras similares.

Modifiquemos nuestra clase Producto para añadir un constructor con un argumento por cada propiedad
del objeto.

class Product
{
    private string $title;
    private string $description;
    private float $price;
    private int $stock;

    public function __construct(
        string $title,
        string $description,
        float $price,
        int $stock,
    )
    {
        $this->title = $title;
        $this->description = $description;
        $this->price = $price;
        $this->stock = $stock;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function getDescription()
    {
        return $this->description;
    }

    public function getPrice()
    {
        return $this->price;
    }

    public function getStock()
    {
        return $this->stock;
    }
}

Para usar la clase emplearemos ahora una lista de productos, los cuales podrían ser leídos de alguna
base de datos o proporcionados por una interfaz de usuario.

Luego esa lista de productos la recorreremos con un bucle foreach y crearemos un objeto por cada
producto.

$items = [
    [
        'title' => 'Pasta dental',
        'description' => 'Producto de higiene bucal',
        'price' => 39.9,
        'stock' => 4,
    ],
    [
        'title' => 'Crema corporal humectante',
        'description' => 'Producto dermatológico',
        'price' => 50.2
        'stock' => 6,
    ],
    [
        'title' => 'Protector Solar 50+fps',
        'description' => 'Protector solar facial',
        'price' => 50.2
        'stock' => 10,
    ],
    [
        'title' => 'Aspirina',
        'description' => 'Tableta ácido acetilsalicílico',
        'price' => 57
        'stock' => 12,
    ],
    [
        'title' => 'Enjuague bucal',
        'description' => 'Producto de higiene bucal',
        'price' => 57
        'stock' => 12,
    ],
];

$ProductList = [];
foreach($items as $item){
    $ProductList[] = new Product(
        $item['title'],
        $item['description'],
        $item['price'],
        $item['stock'],
    );
}

Con esto ya tendríamos un listado de objetos, que de momento solo es un conjunto de datos donde todos
comparten el mismo comportamiento, lo cual de momento puede parecer mucho código para lo que
realmente sirve.

Para cambiar un poco esto y empezar a tener noción del potencial de la POO modifiquemos nuestro
ejemplo añadiendo más lógica para una situación común.

Para actualizar el comportamiento de todos nuestros objetos tipo producto solo hace falta modificar
una sola pieza del software, que en este caso es la clase Product.

Si tuviésemos que aplicar un impuesto al precio de los productos en la misma clase podríamos definir
en una constante de clase cual es el impuesto fijo a aplicar por ejemplo, o si necesitáramos un
método para imprimir la lista de productos en cierto formato

class Product
{
    const 
    private string $title;
    private string $description;
    private float $price;
    private int $stock;

    public function __construct(
        string $title,
        string $description,
        float $price,
        int $stock,
    )
    {
        $this->title = $title;
        $this->description = $description;
        $this->price = $price;
        $this->stock = $stock;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function getDescription()
    {
        return $this->description;
    }

    public function getPrice()
    {
        return $this->price;
    }

    public function getStock()
    {
        return $this->stock;
    }
}

En resumen

Con esto ya tenemos la sintaxis básica para trabajar con objetos en PHP, ya que ahora conocemos las
clases, que son los planos que definen y permiten crear objetos y como se definen las propiedades y
los métodos dentro de ellas.