This page was exported from Recursos para programadores [ https://eldesvandejose.com ]
Export date: Sat Dec 15 19:08:18 2018 / +0000 GMT

PHP-TUT-19 Orientación a objetos en PHP




Empezamos aquí con un artículo tan breve en cuanto a contenido, como interesante desde el punto de vista de nuestras futuras aplicaciones prácticas, tal como veremos en seguida.


La Programación Orientada a Objetos (POO, en adelante) es la tendencia actual de todos los lenguajes de alto nivel, dadas las posibilidades que abre. Básicamente se trata de considerar analogías entre las situaciones que tenemos que resolver mediante la programación y los objetos del mundo real a los que estamos acostumbrados. En este artículo aprenderemos a entender esa consideración y a utilizarla en nuestro favor.


CARACTERÍSTICAS DE LA POO


La POO basa las ventajas que nos ofrece en tres características principales:



  • Abstracción.

  • Reutilización.

  • Actualización.


Para entender estas características, vamos a considerar la analogía con un objeto del mundo real: un automóvil. Seguramente conduces uno todos los días, desde tu casa a tu lugar de trabajo o a cualquier otra parte. Sin embargo, a menos que seas mecánico, no tienes por qué saber cómo funcionan los engranajes de la caja de cambios, o las bielas, los diferenciales, la bomba de inyección, etc. Quizás nunca te hayas parado siquiera a pensarlo, pero en eso consiste la abstracción. Usas un objeto, le sacas todo el rendimiento que puedes, pero no sabes cómo funciona internamente y, en realidad, no te hace ninguna falta. Después de todo, si tu coche sufre una avería, aunque supieras arreglarla no tendrías ni tiempo, ni las herramientas adecuadas. Así pues, ¿para qué vas a saber de mecánica? Con la POO pasa lo mismo. Podrás incluir en tus scripts determinados módulos de código que hagan lo que necesitas, sin saber realmente cómo funcionan "por dentro".


La reutilización es una de las posibilidades más interesantes de la POO. Volviendo a la analogía de nuestro ejemplo, tú usas tu coche para ir a trabajar pero, cuando llega el domingo, lo usas para salir al cine. Seguramente, lo emplees también para ir de compras, o para desplazamientos más largos durante tus vacaciones. Con los objetos de software ocurre lo mismo. Tienes un objeto destinado, por ejemplo, a realizar un proceso determinado con la información procedente de una base de datos. Ese mismo objeto puede hacer lo mismo con otra información procedente de cualquier otra fuente. Simplemente incluyes el objeto en los scripts que creas y lo usas de acuerdo a tus necesidades, con pocas o ninguna modificación.


Por último, considera la actualización. Al igual que puedes instalarle a tu coche un nuevo radio CD, o una batería más potente, también puedes actualizar, de la forma adecuada, los objetos de software para dotar de nuevas funcionalidades a tus scripts, o bien mejorar las actuales.


CONCEPTOS BÁSICOS


La POO se basa en los siguientes conceptos fundamentales:



  • Clases

  • Objetos

  • Herencia

  • Propiedades

  • Métodos

  • Eventos (en algunos entornos de programación, no en PHP)


Para crear un objeto necesitamos tener lo que se llama una clase. Podemos considerar las clases como moldes, a partir de los que se crean los objetos. Volviendo a las analogías con el mundo real, tu coche está formado por una carrocería, que ha sido fabricada en unos moldes de estampación. Otros elementos, como el bloque del motor o el volante, han sido fabricados en unos moldes de fusión. Estos moldes existen también en el mundo de la programación. A partir de estos moldes se crean los objetos.


Tu coche tiene unas características que lo definen. Usa tal o cual combustible, es de un determinado color, tiene un tamaño concreto, etc. Los objetos de software también tienen unas características, en forma de variables, que se llaman propiedades.


El coche implementa determinadas funcionalidades. Puedes poner el motor en marcha, acelerar, frenar, bajar o subir las ventanillas, etc. Los objetos hacen uso de unas funciones para lograr su objetivo. Éstas se llaman métodos.


Cuando se saca un nuevo modelo de coche, el fabricante crea unos nuevos moldes para las piezas de la carrocería, o nuevos esquemas de los circuitos electrónicos. Y, normalmente, no los crea a partir de cero. Puede coger el molde del antiguo modelo y, a partir de este, crear un molde nuevo, modificando un poco el último. En POO esto se llama herencia. Se crea una clase a partir de otra, y se le implementan nuevas propiedades y/o métodos, con lo que los objetos que se crean a partir de la segunda clase tendrán las propiedades y métodos de la primera, y también los nuevos.


Cuando se crea un objeto a partir de una clase, se dice que instanciamos la clase en un objeto.


CREACIÓN Y USO


Con la teoría y las analogías que hemos visto ya es suficiente. Vamos a pasar a crear nuestras propias clases y objetos, así como a implementar propiedades y métodos.


Antes de crear un objeto necesitamos disponer de la clase a partir de la que se instanciará dicho objeto. Para crear una clase usamos la sentencia class, seguida del nombre de la clase que vamos a crear y del cuerpo de la clase, que es donde se definen las propiedades y métodos que luego tendrán los objetos de esa clase. La sintaxis genérica obedece al siguiente esquema:


class nombreDeLaClase {

    propiedades

    métodos

}


A partir de que la clase haya sido definida podemos crear todos los objetos que necesitemos de dicha clase. Para ello usamos el operador new, tal como se ve en la siguiente sintaxis genérica:


$objeto = new nombreDeLaClase();


Para empezar a familiarizarnos con esta forma de trabajo nada mejor que ver un ejemplo de su uso. Para ello vamos a ver un ejemplo muy sencillo, en el que se define una clase destinada a sumar dos números. Mira el script claseSimple.php:


<?php
// Aqúí empieza la definición de la clase.
class sumador {
public function sumador(){
}
public function sumar($sum_1, $sum_2){
$total=$sum_1+$sum_2;
return $total;
}
}
// Terminamos la definición de la clase.
// ===========================================
// Instanciamos la clase en un objeto.
$hacerSumas = new sumador();
// Llamamos al método sumar del objeto que hemos creado.
$resultado = $hacerSumas->sumar(2,3);
// Mostramos el resultado.
echo "La suma de 2 + 3 da ".$resultado.".";
?>

Al cargar el script en el navegador vemos el resultado en el navegador.


Si estás pensando que para obtener "eso" no hacía falta tanto código, tienes razón. Sin embargo, el listado de este script nos va a permitir anclar conceptos necesarios, y eso es lo que importa.


Vamos a empezar viendo cómo definimos la clase que vamos a emplear. Fíjate en la primera parte del código:


// Aqúí empieza la definición de la clase.

  class sumador {

      public function sumador (){

      }

      public function sumar($sum_1, $sum_2){

          $total=$sum_1+$sum_2;

          return $total;

      }

  }

// Terminamos la definición de la clase.


Observa que, dentro del cuerpo de la clase, hay una función (un método) que tiene el mismo nombre que dicha clase. Esto es lo que se llama un constructor. Sirve para poder crear objetos de dicha clase y que éstos tengan las propiedades y métodos definidos en ella. En este ejemplo concreto, el constructor no sirve para nada. De hecho puedes suprimirlo y el script te funcionará igualmente. Sin embargo, he querido incluirlo como una primera toma de contacto con esta idea. En el próximo ejemplo veremos un uso real del mismo. De hecho, aunque no tenga ningún uso, cómo en este caso, es aconsejable incluirlo siempre, por claridad del código.










ATENCIÓN. Por ahora, ingora el modificador public que precede a la definición de los métodos. Hablaremos de eso en este mismo artículo, un poco más adelante.

Observa la función sumar(). Es la definición de un método. Cuando se crea una clase (familiarízate ya con la terminología adecuada), las funciones se llaman métodos. Las variables propias de la clase (en este primer script no hay ninguna) se llaman propiedades. Quiero llamar tu atención acerca de lo que son "variables propias de la clase": son aquéllas que se definen en el cuerpo de la clase (no dentro de un método) y serán heredadas por los objetos que implementemos a partir de dicha clase.


Siguiendo con el script, vemos cómo creamos un objeto, así:


$hacerSumas = new sumador();


A continuación hacemos una llamada al método sumar del objeto que hemos creado, tal como ve en la siguiente línea:


$resultado = $hacerSumas->sumar(2,3);


Fíjese en el operador -> que usamos para referirnos a una propiedad o un método de un objeto. La sintaxis genérica es la siguiente:


$objeto->propiedad

$objeto->metodo (argumentos, si proceden


 








ATENCIÓN. Este operador puede inducir un poco a confusión a las personas que "vienen" de otros lenguages, cómo C++ o Java, ya que el operador que separa el nombre del objeto del de la propiedad o método es el punto (.) en la mayoría de los lenguajes de programación. En PHP el punto se usa para concatenar cadenas, cómo ya sabes. Son pequeñas peculiaridades del lenguaje, a las que debemos acostumbrarnos.

Quiero llamar tu atención respecto a un punto de la sintaxis. Fíjate en el ejemplo genérico que acabamos de citar que la propiedad no lleva el signo $, aún tratándose de una variable. Esto es así porque este signo ya precede al nombre del objeto. Cuando se usa esta notación, el nombre de la propiedad se escribe sin $. Lo contrario producirá que la propiedad no sea accesible y, por lo tanto, no se le puede asignar un valor, ni leerlo.


Antes de pasar al siguiente ejemplo debe saber que en la POO existe la referencia $this, que se usa como comodín para referirse al objeto que estamos manejando sin especificar su nombre. Este concepto, así como el de propiedades, está ilustrado en el siguiente ejemplo, llamado claseFuncional.php:


<?php
// Empieza la definición de la clase.
class coche {
// Se definen las propiedades que tendrán los objetos de esta clase.
public $marca;
public $modelo;
public $color;

// El constructor
public function coche($marca, $modelo, $color){
$this->marca = $marca;
$this->modelo = $modelo;
$this->color = $color;
}

public function mostrar (){
echo "<table width='200' border='2' cellpadding='2' cellspacing='0'>";
echo "<tr><td width='50%'>MARCA</td><td width='50%'>".$this->marca."</td></tr>";
echo "<tr><td>MODELO</td><td>".$this->modelo."</td></tr>";
echo "<tr><td>COLOR</td><td>".$this->color."</td></tr>";
echo "</table>";
}
}
// Termina la definición de la clase.
// =========================================
// Se crean tres objetos formando una matriz
$movil[0] = new coche("Peugeot", "607", "Verde");
$movil[1] = new coche("Renault", "Master", "Blanco");
$movil[2] = new coche("Cadillac", "Seville", "Azul");

/* Mediante un bucle se ejecuta el método mostrar de cada uno de los objetos.*/
for ($contador=0;$contador<3; $contador++) $movil[$contador]->mostrar();
?>

Al ejecutar este script verás en tu navegador el resultado del uso de la clase.


Como en el caso anterior, vamos a ir despiezando el código, para ver cómo funciona. En primer lugar tenemos la definición de la clase coche, tal como aparece a continuación:


class coche {
// Se definen las propiedades que tendrán los objetos de esta clase.
public $marca;
public $modelo;
public $color;

// El constructor
public function coche($marca, $modelo, $color){
$this->marca = $marca;
$this->modelo = $modelo;
$this->color = $color;
}

public function mostrar (){
echo "<table width='200' border='2' cellpadding='2' cellspacing='0'>";
echo "<tr><td width='50%'>MARCA</td><td width='50%'>".$this->marca."</td></tr>";
echo "<tr><td>MODELO</td><td>".$this->modelo."</td></tr>";
echo "<tr><td>COLOR</td><td>".$this->color."</td></tr>";
echo "</table>";
}
}

Lo primer que ves es que declaramos tres variables. Son propiedades que tendrán todos los objetos que se instancien a partir de la clase.


Observa el método constructor, que aparece resaltado. Recibe tres argumentos que aparecen como variables. Dentro de este método se asigna cada argumento a una de las propiedades del objeto. ¿De qué objeto? Del que se está creando en ese momento. Recuerde: es un constructor. Este método se ejecuta cada vez que se crea un objeto, y sólo entonces. Observa que nos referimos al objeto en proceso, mediante la referencia $this que actúa cómo comodín, por expresarlo en un lenguaje coloquial. Para crear un objeto en nuestro ejemplo usamos una sentencia como la siguiente:


$movil[0] = new coche("Peugeot", "607", "Verde");


El nombre del objeto es un elemento de una matriz. Los objetos pueden agruparse en matrices, igual que las variables. Pero eso no importa ahora. Lo que nos interesa es conocer el proceso. Cuando creamos un objeto como en este ejemplo, el operador new invoca al constructor de la clase. Vea que la invocación se hace pasando tres cadenas como parámetros. Estas se alojan en las variables que hay en la definición del método. No confunda estas variables con las propiedades del objeto que se crean dentro del cuerpo del constructor. A pesar de tener el mismo nombre, las propiedades (variables de la clase) no tienen nada que ver con los argumentos que recibe el constructor y, por eso, dentro de éste, asignamos cada argumento a la variable de objeto correspondiente.


Lo último que vemos es un bucle que recorre cada elemento de la matriz de objetos, llamando al método mostrar de cada objeto. Este método se encarga de crear una tabla y mostrar el valor de las propiedades. A partir de que el objeto ha sido creado, podemos hacer con él lo que queramos.


Como he mencionado anteriormente, una de las características de la POO es la abstracción. De hecho, cuando se usa esta técnica lo normal es que la definición de la clase se encuentre en un fichero aparte, y que sea llamada desde el script mediante include() o require(). Y, de hecho, usted lo único que necesita saber acerca de una clase es qué propiedades y métodos tienen los objetos que se implementen a partir de la misma. La operativa de esos métodos "por dentro" ya no nos interesa. Incluso puede que la clase la haya creado otro desarrollador, en vez de tú mismo, y no sepas cómo opera "por dentro". A ti te dicen las propiedades que tienes disponibles, los métodos que puedes usar y lo que hacen, y eso es suficiente.


Por supuesto, siempre es bueno conocer las clases que usamos, ya que, de este modo, podremos actualizarlas o modificarlas nosotros mismos si lo necesitamos, pero no siemrpe es el caso.


ÁMBITO DE VARIABLES Y MÉTODOS


Antes hemos dejado un poco de lado el modificador public al definir las variables y métodos de las clases de prueba que hemos creado. Cuando se definen clases es importante saber que hay determinadas propiedades y métodos que se usan "internamente", pero no deben ser accesibles desde los objetos. En cambio, otros (cómo los usados hasta ahora) si deben serlo. Para ello contamos con los modificadores public y private.


Una propiedad o método de una clase siempre lleva un modificador de acceso. Si no lo ponemos, se toma, por defecto public.


Y ¿qué quiere decir esto? Vamos a suponer una clase muy sencillita, que tiene un método que calcula el área de un círculo, dado su radio. El listado, calculaArea.php, aparece a constinuación:


<?php
// Empieza la definición de la clase.
class calculaArea {
// Se definen las propiedades que tendrán los objetos de esta clase.
public $radio;
private $valor_de_pi = 3.1415927;
public $area;

// El constructor
public function calculaArea($valorDelRadio){
$this->radio = $valorDelRadio;
}

public function calcular (){
$this->area = $this->valor_de_pi * (pow($this->radio, 2));
return $this->area;
}
}
// Termina la definición de la clase.
// =========================================
// Se crean un circulo
$objetoCirculo = new calculaArea(10);
echo "La superficie es: ".$objetoCirculo->calcular();
?>

Esto te calcula el área de un círculo a partir de su radio. Cómo sabes, la fórmula es π * r2. El valor de pi (mejor lo ponemos así) es fijo. Aunque sea una variable del objeto, no debe poder modificarse, ni acceder a ella, desde el exterior de la clase. Por esta razón la declaramos cómo private. Para entender esto, añade, al final de tu script, la siguiente línea:


echo "PI vale: ".$objetoCirculo->valor_de_pi;


Ahora trata de ejecutar de nuevo el script.


Verás en pantalla el error siguiente:


Fatal error: Uncaught Error: Cannot access private property calculaArea::$valor_de_pi


Nos dice que no podemos acceder a una variable privada. Una propiedad privada la maneja la clase internamente, pero no podemos acceder a ella desde un objeto.


Lo mismo es aplicable a los métodos. Vamos a ver una variante de la clase anterior, llamada metodo_privado.php:


<?php
// Empieza la definición de la clase.
class calculaArea {
// Se definen las propiedades que tendrán los objetos de esta clase.
public $radio;
private $valor_de_pi = 3.1415927;
public $area;

// El constructor
public function calculaArea($valorDelRadio){
$this->radio = $valorDelRadio;
}

private function calcular (){
$this->area = $this->valor_de_pi * (pow($this->radio, 2));
}

public function mostrarArea(){
$this->calcular();
return $this->area;
}
}
// Termina la definición de la clase.
// =========================================
// Se crean un circulo
$objetoCirculo = new calculaArea(6);
echo "La superficie es: ".$objetoCirculo->mostrarArea();
?>

El método calcular() lo hemos definido ahora cómo privado. Esto hace que no sea practicable desde el exterior de la clase. Por esta razón, hemos debido añadir un método nuevo que llama a calcular desde dentro de la clase, y retorna el valor calculado.


Si intentas llamar al método calcular() directamente desde el objeto cómo hacíamos en el ejemplo anterior, obtendrás un error.


Y¿Para que nos sirve esto? Bien. Si miramos los ejemplos vemos que el que usa un método privado tiene más código para obtener el mismo resultado. Esto es así en este caso pero, cuando se crean clases con funcionalidades extensas y complejas, proteger el acceso a determinados métodos y propiedades evita que se puedan cambiar desde fuera por error, y facilita el uso de las clases, aunque, inicialmente, parezca más trabajo.


ACCEDER A VARIABLES PRIVADAS


Puede darse el caso de que, bajo determinadas circunstancias, debas poder acceder desde fuera de la clase a variables privadas. Para ello empleamos unos métodos específicos llamados, genéricamente, getters y setters. Un getter es un método que te permite leer el contenido de una variable privada. Un setter te permite modificarlo. Supongamos el caso de la clase que hemos usado para calcular el área de un círculo. Tenemos cómo privada la variable $valor_de_pi. Si queremos que, en algún momento, se pueda leer desde fuera, definiremos, en la clase, un método cómo el siguiente:


public get_pi(){

    return $this->valor_de_pi;

}


Si luego, en el código del script, ya fuera de la clase, queremos leer la variable $valor_de_pi de un objeto que hayamos creado, incluiremos la siguiente línea:


echo $objeto->get_pi();


Esto no da ningún error. El método get_pi() está declarado cómo public, por lo que es accesible desde fuera de la clase. El método en sí está definido dentro de la clase, por lo que sí puede acceder al valor de una variable privada.


Con los setters ocurre lo mismo. Si queremos modfificar el valor de pi (por ejemplo, para darle mayor precisión), deberemos crear un método cómo el siguiente:


public set_pi($nuevoValor){

    $this->valor_de_pi = $nuevoValor;

}


Así, luego, en el script, fuera de la clase, podemos usar algo así:


$objeto->set_pi(3.141592653);


Estamos en las mismas. El método set_pi() es públco, por lo que es accesible desde fuera de la clase. Y cómo está dentro de la clase, puede modificatr una variable privada.


DE CLASE O DE OBJETO


Siendo un poco estrictos con el ejemplo anterior, no parece tener ningún sentido que el valor de pi esté presente en cada objeto. El valor de pi siempre será el mismo y cada objeto círculo que creemos en la clase debe tener ese mismo valor. Si lo modificamos para darle mayor precisión, cómo hemos hecho con el ejemplo del setter, debería estar disponible el nuevo valor para todos los objetos de la clase, ya sea que estén ya creados, o que se creen en adelante.


Para una variable que deba ser igual para todos los objetos de la clase, recurrimos a lo que se llaman variables de clase, que se declaran con el modificador static. Esto hace que no se pueda acceder a ellas desde objetos, sino con el nombre de la clase. Vemaos un retoque de los ejemplos anteriores, para entender cómo usar variables de clase. Lo hemos llamado propiedades_de_clase.php:


<?php
// Empieza la definición de la clase.
class calculaArea {
// Se definen las propiedades que tendrán los objetos de esta clase.
public $radio;
private static $valor_de_pi = 3.1416;
public $area;

// El constructor
public function calculaArea($valorDelRadio){
$this->radio = $valorDelRadio;
}

private function calcular (){
$this->area = calculaArea::$valor_de_pi * (pow($this->radio, 2));
}

public static function get_pi(){
return calculaArea::$valor_de_pi;
}

public static function set_pi($nuevoValor){
calculaArea::$valor_de_pi = $nuevoValor;
}

public function mostrarArea(){
$this->calcular();
return $this->area;
}
}
// Termina la definición de la clase.
// =========================================
// Se crean un circulo
$objetoCirculo = new calculaArea(6);
echo "La superficie es: ".$objetoCirculo->mostrarArea()."<br />";
echo "Fijamos el valor de PI en 3.141592653<br />";
calculaArea::set_pi(3.141592653);
echo "Recalculamos el área.<br />";
echo "La superficie es: ".$objetoCirculo->mostrarArea()."<br />";
?>

Observa que para referirnos a una propiedad de clase ya no empleamos $objeto->propiedad o $this->propiedad, sino clase::$propiedad. Eso hace que el nuevo valor esté disponible para TODOS los objetos de la clase. Del mismo modo, para llamar a un método de clase, no empleamos $objeto->metodo() o $this->metodo(), sino clase::metodo(). En general se definen cómo variables de clase aquellas que deban tener el mismo valor para todos los objetos de la clase, y cómo métodos de clase aquellos que deban actuar igual y estar disponibles con los mismos datos para todos los objetos. Analiza el código para entender cómo funciona. El doble dos puntos (::) se emplea en este constexto y se llama operador de resolución de ámbito.


HERENCIA


Como ha visto en el apartado anterior, los objetos heredan las propiedades y los métodos de la clase a la que pertenecen. Pero el concepto de herencia es más amplio. Puedes, cómo ya hemos comentado, crear una clase a partir de otra. La clase original se conoce, genéricamente, con el nombre de superclase y las clases que se crean a partir de ella se conocen, también genéricamente, como clases derivadas o subclases. Para crear una subclase a partir de una superclase empleamos la palabra clave extends. Veamos un ejemplo general:


class A {

  propiedad_A1

  propiedad_A2

  metodo_A3

  metodo_A4

}


class B extends A {

  propiedad_B1

  metodo_B2

}


Fíjate en que hemos declarado la clase B como derivada de la clase A. Por esta razón, la clase B tiene todas las propiedades y métodos de la clase A, además de los suyos propios. Si ahora creamos un objeto de la clase A, este tendrá las propiedades y métodos de su clase. Si creamos un objeto de la clase B, tendrá los métodos y las propiedades de ambas clases.

Post date: 2016-06-14 12:40:29
Post date GMT: 2016-06-14 12:40:29
Post modified date: 2016-10-06 09:42:01
Post modified date GMT: 2016-10-06 09:42:01
Powered by [ Universal Post Manager ] plugin. HTML saving format developed by gVectors Team www.gVectors.com