Clases y objetos
La programación orientada a objetos nos permite agrupar datos y funcionalidad en un mismo lugar, la clase. A diferencia de la programación basada en procedimientos, en la que los datos se asocian a variables y las funciones operan sobre los datos, la programación orientada a objetos permite mayor nivel de abstracción (ocuparnos menos de los pequeños detalles) con lo que podremos construir aplicaciones más complejas. Con la clase, definimos cómo va a ser la estructura de datos y las funciones que podemos asociar a los datos. Los objetos se crean en base a esta definición. En este caso hablaremos de instancia de clase.
La primera sentencia que hay que conocer es la que nos permite definir una Clase (las clases definen los tipos de objetos).
1 2 3 |
class Producto { // cuerpo de la clase } |
De esta forma, estamos indicando que hay una clase, Producto, la cual podemos utilizar para crear Objetos de ese tipo.
1 2 |
$producto1 = new Producto(); $producto2 = new Producto(); |
Los datos que queramos almacenar sobre el objeto, los definimos dentro de la clase. Los llamaremos propiedades del objeto. Son las propiedades las que nos permiten diferenciar unos objetos de otros.
1 2 3 4 5 6 7 |
class Producto { public $nombre; public $descripcion; public $color; public $peso = 0; public $precio = 0; } |
Definidas las propiedades para la clase Producto, podemos crear dos objetos distintos con características distintas.
1 2 3 4 5 6 7 |
$producto1 = new Producto(); $producto2 = new Producto(); $producto1->nombre = "pelota"; $producto1->descripcion = "De cuero con uniones pegadas"; $producto2->nombre = "raqueta"; $producto2->peso = 30; |
Decíamos que la programación orientada a objetos nos permite agrupar datos y funcionalidad en un mismo lugar. Para definir la funcionalidad que tendrá cada objeto de la clase, definiremos métodos (funciones asociadas al objeto).
1 2 3 |
function getDescuentoProducto($dto) { return (($this->precio) * (1 - $dto); } |
Constructor de Clase y uso de this
En este caso, definimos un método que nos devuelve el precio de un producto con un descuento que le pasamos como parámetro al método. $this hace referencia al objeto que llama al método.
1 2 3 4 5 |
$producto3 = new Producto (); $producto3->precio = 100; $descuento = $producto3->getDescuento(20); // $descuento == 80 |
Es habitual definir en la clase un método especial llamado Constructor. El constructor es un método que se ejecuta cuando se crea un objeto de la clase. Para definirlo, usamos la palabra reservada ‘__construct‘. Esto nos permite inicializar valores del objeto o realizar las operaciones que creamos necesarias.
1 2 3 4 5 6 7 8 9 |
function __construct( $nombre, $descripcion, $color, $peso, $precio) { $this->nombre = $nombre; $this->descripcion = $descripcion; $this->color = $color; $this->peso = $peso; $this->precio = $precio; } $producto4 = new Producto ('cubo', 'metálico con asa', 'gris', 15, 100); |
Argumentos de métodos
A la hora de definir los métodos de una clase, es bastante habitual que éstos tengan parámetros. En PHP no es necesario definir el tipo del argumento (si es un string, array y objeto). Esto permite mayor flexibilidad a la hora de programar, pero es nuestra responsabilidad chequear que el tipo es el adecuado antes de manipular los datos que recibimos.
En el caso de recibir objetos de una clase como parámetro, existe la opción de especificar el tipo del objeto. Esto es bastante útil por cuestiones de claridad, ya que ayuda a identificar el tipo que espera recibir el método.
1 2 3 4 5 6 7 |
class ImpresionProducto { public function write(Producto $Producto1 ) { $str = "{$Producto1->nombre}" . "{$Producto1->descripcion}"; } } |
Herencia
La herencia nos permite crear una clase a partir de otra, de forma que podemos aprovechar su propiedades (datos) y métodos (funciones), es decir, podemos aprovechar la estructura definida en una clase para crear otra, generalmente, más especializada.
Siguiendo con nuestro ejemplo, podríamos crear una clase nueva a partir de Producto. Supongamos que queremos tener productos orgánicos que tienen caducidad. Su definición quedaría de la siguiente forma.
1 2 3 4 5 6 7 8 9 10 |
class ProductoOrganico extends Producto { public $caducidad; function __construct($nombre, $descripcion, $color, $peso, $precio, $caducidad) { parent::__construct($nombre, $descripcion, $color, $peso, $precio); $this->caducidad = $caducidad; } } |
Para que la nueva clase herede de la clase Producto, hacemos uso de la palabra reservada extends, que indica que la clase ProductoOrganico hereda de la clase Producto. A la hora de definir el constructor de la nueva clase, usamos la palabra reservada parent, con la que hacemos referencia a la clase padre de la clase actual (en el ejemplo, parent se refiere a Producto). Además, el operador de resolución de alcance ‘::‘ permite hacer referencia a propiedades o métodos de clases sin tener que crear objetos.
Métodos y propiedades static (estáticos)
Hasta ahora, hemos visto que una clase define un tipo de objeto que podemos crear con sus características únicas (sus propiedades) y con el que podemos operar (a través de sus métodos disponibles). Vemos que los objetos tienen carácter dinámico ya que se pueden crear, manipular y destruir en tiempo de ejecución. Las clases, son de carácter estático ya que las definimos cuando programamos y desde entonces no se modifican.
Los métodos y propiedades estáticas tienen sentido en el ámbito de la clase. Los métodos estáticos pueden ser llamados sin necesidad de tener un objeto creado. Igual ocurre con las propiedades estáticas, son propiedades de clase y son accesibles sin necesidad de crear objetos. Para poder usar las propiedades y los métodos estáticos, usaremos el operador ya comentado ::
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class ProductoCadenaEstatico{ static public $cantidad = 0; // propiedad estática public $str; static public function hola() { // método estático print "Hola"; } public function __construct($str) { self::$cantidad++; $this->str = $str; } public funcion verCadena() { return $this->str; } } print ProductoCadenaEstatico::$cantidad; // imprimiría 0 ProductoCadenaEstatico::hola(); // podemos llamar $a = new ProductoCadenaEstatico("producto cadena inicial"); print ProductoCadenaEstatico::$cantidad; // imprimiria 1 |
Gestión del acceso a propiedades y métodos
Siguiendo el principio de encapsulamiento, PHP nos permite definir tres tipos de visibilidad para nuestras propiedades y métodos:
- Public. Accesible desde cualquier contexto.
- Private. Sólo accesible por la propia clase.
- Protected. Sólo accesible por la propia clase y subclases (otras clases que hereden de ella).
Abastracción
Hablaremos de abstracción cuando queramos declarar una clase o un método pero que no implementaremos directamente. Serán las clases que hereden de ella las que se encarguen de implementarla. Una clase abstracta no se puede instanciar (no se pueden crear objetos de ella). Una clase que tenga un método abstracto tendrá que ser declarada como abstracta.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
abstract Class Objeto { public $ID; abstract public function getID(); } Class Producto extends Objeto { public $nombre; public $descripcion; public $color; public $peso = 0; public $precio = 0; public function getID() { return $this->ID + $nombre; } } Class ProductoOrganico extends Producto { public $caducidad; public function getID() { return $this->ID + $nombre + $caducidad; } } |
Interesante artículo de como prevenir inyecciones SQL en PHP.
http://indieteq.com/index/readmore/how-to-prevent-sql-injection-in-php
Si que es interesante. Una buena opción para evitar ataques de este tipo es usar alguna librería tipo HTTPFoundation (Componente de Symfony). De esta forma podemos tener solucionados desde el principio toda una habitual variedad de fallos de seguridad.