viernes, 23 de noviembre de 2012

PHP avanzado: orientación a objeto

PHP A menudo suele decirse que PHP 5 es un lenguaje de programación Orientado a Objetos a diferencia de las versiones anteriores de PHP, pero ¿Que significa eso? En este artículo voy a tratar de explicar que es la programación Orientada a Objetos y cuales de las características de este paradigma de la programación implementa PHP 5.


¿Qué es la Programación Orientada a Objetos?

Sobre este tema hay amplia documentación en Internet, así que seré breve. La Programación Orientada a Objetos (OOP, Object Oriented Programming) es un conjunto de técnicas de programación que permiten encapsular los datos y las operaciones en unas estructuras llamadas Clases. A una instancia de una clase se la denomina Objeto. Los objetos interaccionan entre si a través de los Métodos que exponen las clases. Esta forma de programar permite describir de forma más adecuada el mundo real que la programación estructurada o tradicional.

En la actualidad, existen variedad de lenguajes de programación que soportan la orientación a objetos. Cada lenguaje aporta algo distinto, aunque la mayoría tiene características comunes. Las más importantes son:

PHP 5 incorpora estas características y algunas otras por eso se dice que es un lenguaje orientado a objetos. Lo veremos a continuación. PHP 4 permitía crear clases e incorporaba algunas características de la orientación a objetos, pero no todas por lo que no se consideraba un lenguaje de programación orientado a objetos.


Clases y objetos.

Una clase es una estructura que encapsula los datos y las operaciones a realizar sobre esos datos. En PHP 5 los datos serán variables miembro y las operaciones serán métodos (funciones miembro). Para acceder a los datos y métodos desde dentro de la clase se utiliza la meta variable $this junto al operador "->".

class NombreClase {

  var $dato1;
  var $dato2;

  function metodo1() {
    echo $this->dato1;
  }

  function metodo2() {
    echo $this->dato2;
  }
}

Por contra un objeto será una instancia de una clase. Para acceder a los datos y métodos de un objeto se utiliza el operador "->".

$objeto = new NombreClase();
$objeto->metodo1();
echo $objeto->dato1;

Visibilidad de datos y métodos.

En PHP 5 se pueden utilizar las palabras clase public, private y protected para definir la visibilidad de cada variable miembro y método de una clase. Si no se define se asume que tiene visibilidad pública.

  • public: Visibilidad pública. Todo el mundo puede acceder a esa estructura.
  • private: Visibilidad privada. Sólo los métodos de la propia clase pueden acceder a esa estructura.
  • protected: Visibilidad protegida. Sólo los métodos de la propia clase y de las clases derivadas pueden acceder a esa estructura. Lo veremos cuando hablemos de la herencia.
class NombreClase {

  public $datoPublico;
  private $datoPrivado;
  protected $datoProtegido;

  public function metodoPublico() { /* ... */ }
  private function metodoPrivado() { /* ... */ }
  protected function metodoProtegido() { /* ... */ }
}

$objeto = new NombreClase();

echo $objeto->datoPublico; // Correcto
echo $objeto->datoPrivado; // Error
echo $objeto->datoProtegido; // Error

$objeto->metodoPublico(); // Correcto
$objeto->metodoPrivado(); // Error
$objeto->metodoProtegido(); // Error

Constantes dentro de clases.

Una constante es una variable que mantiene el mismo valor durante toda su vida. Se puede definir constantes dentro de una clase utilizando la palabra clave const. Para acceder a una constante desde dentro de la clase se utilizará la palabra clave self junto al operador de ámbito "::". Para acceder a una constante desde fuera de la clase (si la constante es pública) se utilizará el nombre de la clase junto con el operador de ámbito "::".

class NombreClase
{
    const CONSTANTE = 'valor';

    function escribirConstante() {
        echo self::CONSTANTE;
    }
}

$objeto = new NombreClase();
$objeto->escribirConstante();

echo NombreClase::CONSTANTE;

Variables y métodos estáticos.

En PHP 5 además de constantes pueden definirse variables estáticas, que son aquellas que tienen una única instancia para todos los objetos de la clase. Una variables estática tiene el mismo valor en todos los objetos de la clase igual que las constantes, pero a diferencia de éstas, su valor puede ser modificado. No se puede acceder a las variables estáticas a través del operador "->". Hay que usar el operador de ámbito "::".

class UnaClase {

    public static $varEstatica = 1;

    public function valorVarStatica() {
        return self::$varEstatica;
    }

    public function establecerVarEstatica($valor) {
        self::$varEstatica = $valor;
    }
}

$objeto1 = new UnaClase();
$objeto2 = new UnaClase();

$objeto1->establecerVarEstatica(2);
echo $objeto1->valorVarStatica(); // Imprimirá 2
echo $objeto2->valorVarStatica(); // Imprimirá 2
echo UnaClase::$varEstatica; // Imprimirá 2

También pueden declararse métodos estáticos que son aquellos que se pueden invocar sin tener creada una instancia del objeto usando el operador de ámbito "::".

class UnaClase {

    private static $varEstatica = 1;

    public static function obtenerVarStatica() {
        return self::$varEstatica;
    }
}

echo UnaClase::obtenerVarStatica(); // Imprimirá 1

Herencia.

La herencia es un mecanismo por el cual una clase hereda características de otra clase (datos y métodos). Cuando una clase hereda de otra se dice que la primera (clase hija) deriva de la segunda (clase base). La clase hija tendrá acceso a los datos y métodos públicos o protegidos de la clase base, pero no a los privados. Para indicar herencia en PHP 5 se utiliza la palabra clave extends.

class ClaseBase {

  public $dato1;

  public function metodo1() { /* ... */ }
}

class ClaseHija extends ClaseBase {

  public $dato2;

  public function metodo2() { /* ... */ }
}

$objeto1 = new ClaseBase();
echo $objeto1->dato1;
$objeto1->metodo1();

$objeto2 = new ClaseHija();
echo $objeto2->dato1;
echo $objeto2->dato2;
$objeto2->metodo1();
$objeto2->metodo2();

Herencia múltiple.

La herencia múltiple es un tipo particular de herencia en que una clase hija deriva de más de una clase base. A pesar de que ésta es una característica presente en muchos lenguajes de programación orientados a objetos, PHP 5 no permite la herencia múltiple.


Clases abstractas.

Las clases abstractas son aquellas que no pueden ser instanciadas directamente, sino que necesitan tener una clase derivada. Las clases abstractas tienen métodos abstractos que son aquellos que se definen en la clase base y se implementan en las clases derivadas. En PHP 5 se utiliza la palabra clave abstract para definir clases y métodos abstractos. Veamoslo con un ejemplo:

abstract class Figura
{
  // Miembro protegido
  protected $color;

  // Métodos públicos
  public function establecerColor($color) { $this->color = $color; }
  public function obtenerColor() { return $this->color; }

  // Método abstracto
  abstract public function dibujar();
}

class Cuadrado extends Figura {

  // Miembros
  private $x1;
  private $y1;
  private $x2;
  private $y2;

  public function dibujar() {
    // Se dibuja el cuadrado...
  }
}

class Circulo extends Figura {

  // Miembros
  private $x;
  private $y;
  private $r;

  public function dibujar() {
    // Se dibuja el círculo...
  }
}

Si intentamos crear un objeto de clase Figura se producirá un error. En cambio podemos crear objetos de clase Cuadrado o Circulo. Si intentamos crear otra clase que derive de Figura (por ejemplo Pentagono) y no definimos el método dibujar() también se producirá un error.


Interfaces.

Una interfaz es una estructura similar a una clase abstracta en el sentido que permite definir métodos abstractos que deberán implementarse en las clases que implementen dicha interfaz. La diferencia es que en una interfaz no se pueden implementar métodos (todos los métodos son abstractos) mientras que una clase abstracta puede mezclar métodos abstractos y métodos "normales". En PHP 5 todos los métodos de una interfaz deben ser públicos.

interface NombreInterfaz {

    public function metodo1();
    public function metodo2();
}

class NombreClase implements NombreInterfaz {

    public function metodo1() { /* ... */ }
    public function metodo2() { /* ... */ }
}

Una interfaz es un "contrato" que deben cumplir todas las clases que la implementen. En PHP 5 una clase puede derivar de otra (herencia) y a la vez implementar uno o más interfaces. Hay una restricción que es que los nombres de los métodos abstractos no pueden repetirse entre las diferentes interfaces ni con la clase base.

abstract class ClaseBase {

  public function metodoBase1() { /* ... */ }
  abstract public function metodoBase2();
}

interface Interfaz1 {

  public function metodoInterfaz1();
}

interface Interfaz2 {

  public function metodoInterfaz2();
}

class ClaseHija extends ClaseBase implements Interfaz1, Interfaz2 {

  public function metodoBase2() { /* ... */ }
  public function metodoInterfaz1() { /* ... */ }
  public function metodoInterfaz2() { /* ... */ }
  public function metodoHijo1() { /* ... */ }
}

$objeto = new ClaseHija();
$objeto->metodoBase1();
$objeto->metodoBase2();
$objeto->metodoInterfaz1();
$objeto->metodoInterfaz2();
$objeto->metodoHijo1();

Constructores y destructores.

El constructor es un método especial que permite inicializar las variables miembro de la clase al crear un objeto. El constructor puede tener o no tener parámetros. El destructor también es único y por contra no tiene parámetros. Es invocado por el sistema cuando ya no hay referencias a un objeto y sirve para liberar memoria al destruir el objeto. En PHP 5 se llaman respectivamente __construct() y __destruct().

class Clase1 {
 
  private $var;
 
  public function __construct($var) {
    $this->var = $var;
  }
 
  public function __destruct() {
    $this->var = null;
  }
 
  public function escribir() {
    echo $this->var;
  }
}
 
// El resultado sería => 0
$objeto1 = new Clase1(0);
$objeto1->escribir();
 
// El resultado sería => 7
$objeto2 = new Clase1(7);
$objeto2->escribir();

Desde el constructor y el destructor de una clase derivada se puede llamar al constructor (o al destructor) de la clase padre usando la palabra clave "parent" y el operador de ámbito "::".

class ClaseBase {

  private $var;

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

class ClaseHija extends ClaseBase {

  public function __construct($var) {
    parent::__construct($var);
  }
}

$objeto = new ClaseHija(3);

Sobreescritura.

La sobreescritura consiste en una técnica que permite cambiar el comportamiento de un método de la clase base en la clase derivada.

class ClaseBase {
 
  public function metodo1() {
    echo "1";
  }
}
 
class ClaseHija extends ClaseBase {
 
  public function metodo1() {
    echo "2";
  }
}
 
$objeto1 = new ClaseBase();
$objeto1->metodo1(); // Escribe 1
 
$objeto2 = new ClaseHija();
$objeto2->metodo1(); // Escribe 2

Clases y métodos finales.

Una clase final es aquella que no puede ser derivada. Análogamente un método final es aquel que no puede ser sobreescrito en una clase derivada.

final class Clase1 {
  //...
}

class Clase2 extends Clase1 {
  // Esto da error porque Clase1 está declarado como final.
}

class Clase3 {

  public final function metodo3() {
    //...
  }
}

class Clase4 extends Clase3 {

  public function metodo3() {
    // Esto da error porque metodo3() está declarado como final.
  }
}

Con esto acabo esta guía rápida de referencia para programación orientada a objetos en PHP 5. Más información en el manual oficial de PHP.

No hay comentarios:

Publicar un comentario