php-poo-encapsulacion

Encapsulación

Se refiere a la capacidad de agrupar y condensar distintos elementos en un entorno con límites bien definidos. ¿Cómo lo relaciono a la POO? De manera automática, primero generalizamos —abstracción— y luego establecemos los límites —encapsulación. Sí, la encapsulación está ligada a la abstracción.

ver : Abstracción con PHP y programación orientada a objetos

Empecemos por entender desde lo más básico, es importante comprender estos conceptos muy bien porque de ellos depende nuestra lógica en la aplicación, teniendo un buen nivel de razonamiento sobre estos conceptos resultará más fácil comprender conceptos más difíciles más adelante, confía en mí.

Cuando me preparo para salir en bicicleta no me preocupa el modo en cómo funciona ésta, solo estoy preocupado en la condición de mis piernas, si ya desayuné, y si llevo lo necesario —agua, alimentos— para mi entrenamiento. Una vez en la práctica si necesito ir más rápido en la bicicleta basta con subir una marcha, pero no estoy pensando cómo la bicicleta interactúa con los demás elementos para realizar la acción que le acabo de indicar. Y en especial a mí no me interesa saber cómo ocurre la magia, solo estoy enfocado en subir de marcha, no en el proceso que implica esto.

La encapsulación se encarga de mantener ocultos los procesos internos, dándole al programador acceso sólo a lo necesario, como las APIs, no puedes cambiar procesos, sólo tienes acceso a unos métodos ya definidos. La encapsulación brinda dos ventajas:

  1. Las acciones del usuario pueden ser controladas internamente.
  2. La segunda ventaja es poder realizar cambios/mejoras sin que esto afecte el modo en que los usuarios interactúan con la aplicación. Solo tienes que mantener igual la forma de acceder al método, en el caso de un control remoto, si el botón de apagado se encarga de apagar la televisión entonces que esa siga siendo su acción, así como los botones de volúmen o cambiar de canal, sería raro que al presionar el botón de apagado la T.V. ésta aumente de volumen o cambie de canal.

Ahora, relacionando con POO el aislamiento es algo que debemos tener en cuenta. Cada objeto está aislado del exterior, es un módulo, y cada clase especifica cómo pueden acceder a sus propiedades. El aislamiento protege a las propiedades de un objeto contra su modificación para quienes no tienen derecho a acceder a ellas, solamente los propios métodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no pueden cambiar el estado interno de un objeto de manera inesperada. A esto se le conoce como principio de ocultación.

Tomaré el ejemplo de la hamburguesa.

class Burger {
    $ingredients = [];

    function make($ingredients)
    {
        $this->giveMeIngredients($ingredients);
        $this->prepare();
        $this->cook();
    }

    function giveMeIngredients($ingredients)
    {
        $this->ingredients = $ingredients;
    }

    function prepare()
    {
        // prepare
    }

    function cook()
    {
        // cook
    }
}

La declaración de atributos va precedido de una palabra que puede ser public, private o protected. El ejemplo anterior no tiene establecido el nivel de visibilidad:

  • Public. El atributo o método precedido de public podrá ser leído o llamado desde cualquier parte del código, sea desde la misma clase o fuera de ella, esto significa que también podrá ser alterado sin restricciones, por eso se aconseja que los atributos se declaren como privados salvo casos excepcionales.
  • Private. El atributo o método establecido como private solo puede ser leído desde el interior de la clase. Al intentar acceder desde fuera de la clase obtendríamos un error.
  • Protected. Los atributos o métodos protected son similares a los private, solo se puede acceder a ellos desde el interior de la clase, pero con una diferencia muy útil, las clases heredadas de está también podrán leer y alterar estos atributos.

Ahora, para modificar la visibilidad debemos pensar de forma abstracta, haciendo una analogía de la clase, ¿Al cliente le interesa preparar su hamburguesa? ¿Le interesa cocinarla? No, así que considero que esos métodos por ahora deberían ser privados, ojo, solo estamos trabajando con este pequeño ejemplo, porque lo correcto sería que una clase llamada Chef se encargue de cocinar la hamburguesa, y el mesero la persona encargada de tomar la orden y servir.

private function prepare()
{
    // prepare
}

private function cook()
{
    // cook
}

La propiedad ingredientes también me gustaría hacerla privada, y mediante el método make cada persona establece cómo quiere su hamburguesa. Y con eso, mi variable $ingredients también será privada, no me gustaría que cualquier objeto tuviera el permiso de modificarla.

private $ingredients = [];

private function giveMeIngredients($ingredients)
{
    $this->ingredients = $ingredients;
}

Y el método make lo haré público, porque quiero que sea el único que se puede acceder desde fuera de la clase.

public function make($ingredients)
{
    $this->giveMeIngredients($ingredients);
    $this->prepare();
    $this->cook();
}

Ahora, como he modificado la visibilidad del método ingredients puedo borrarlo de esta función. Y una manera limpia de implementar esto sería la siguiente:

$burger = new Burger();
$ingredients = ["bread", "lettuce", "ketchup"]; // Es una hamburguesa hipster
$burger->make($ingredients);

El objeto $burger no tiene idea de que existe otro método de nombre giveMeIngredints, prepare and cook, con esto encapsulamos nuestras variables porque él solo tiene accedo al método make, que se encarga de hacer la hamburguesa.

NOTA. En caso de omitir el grado de visibilidad se tomará por defecto como public, hay que prestar mucha atención a esto.

Lecturas recomendadas

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Abstracción con PHP y programación orientada a objetos Lección siguiente Organizar código PHP con CS Fixer siguiendo los estándares PSR