Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Índice de contenidos
Introducción............................................................................................................................................................... 3
Objetos y declaración de clases .............................................................................................................................. 4
Introducción ..................................................................................................................................................... 4
Introducción a la programación orientada a objetos ................................................................................. 4
Clases y objetos en PHP.................................................................................................................................. 6
Referencias a objetos ...................................................................................................................................... 7
Expresiones, constructores y destructores ......................................................................................................... 11
Introducción ................................................................................................................................................... 11
Expresiones .................................................................................................................................................... 11
Constructores................................................................................................................................................. 13
Destructores................................................................................................................................................... 14
Métodos public, private y protected..................................................................................................................... 14
Métodos public, private y protected ........................................................................................................... 14
Herencia en PHP ............................................................................................................................................ 17
Operadores y polimorfismo .................................................................................................................................. 22
Métodos y clases abstractas.................................................................................................................................. 26
Interfaces y herencia de interfaces....................................................................................................................... 29
¿Qué es un Interface?.................................................................................................................................... 29
Uso de Interfaces en PHP ............................................................................................................................. 30
Implementando varios interfaces ............................................................................................................... 31
Herencia de Interfaces .................................................................................................................................. 31
Tratamiento de excepciones ................................................................................................................................. 32
Introducción ................................................................................................................................................... 32
Tipos de errores en PHP ............................................................................................................................... 32
Mostrando y ocultando errores................................................................................................................... 33
Función error_reporting() ............................................................................................................................ 34
¿Qué son las excepciones? ........................................................................................................................... 34
Lanzando una excepción .............................................................................................................................. 35
Creación de excepciones .............................................................................................................................. 38
Controlando varias excepciones.................................................................................................................. 39
Página 2 de 39
Introducción
En este tema avanzaremos en el dominio del lenguaje PHP metiéndonos de lleno en uno de sus aspectos más
importantes: la orientación a objetos.
La orientación a objetos es un paradigma de programación que pretende facilitar el desarrollo de código, así como
su mantenimiento y facilidad de compresión, mediante bloques de código específicos que nos permiten moldear en
nuestra aplicación entidades del mundo real.
Si nunca utilizaste orientación a objetos, este tema te supondrá un esfuerzo de compresión adicional, pues
la comprensión de este paradigma tiene una alta carga conceptual. Una vez comprendidos los pilares de
la orientación a objetos, asimilar la sintaxis que PHP nos ofrece para implementarla no supondrá ningún
problema. Además, podrás exportar tus conocimientos a cualquier otro lenguaje orientado a objetos,
como Java o C++.
Posteriormente, hablaremos sobre control de errores mediante excepciones. Las excepciones nos permiten
delimitar partes del código donde pueda suceder un error conocido por el desarrollador, y establecer un
código de respuesta al mismo. Resulta un sistema muy sencillo e intuitivo para crear una aplicación web
robusta.
1
Comprender el término “Programación Orientada a Objetos” y sus conceptos fundamentales.
2
Aplicar dichos conocimientos sobre el paradigma de la orientación a objetos en la realización de aplicaciones
web con PHP.
3
Dominar el uso de la sintaxis PHP para la orientación a objetos: class, abstract, implemet, extend, interface,
etc…
4
Diferenciar y dominar el uso de las diferentes visibilidades de atributos y métodos en función al problema a
resolver.
5
Diferenciar entre los diferentes tipos de errores que existen en PHP, poder interpretarlos y resolverlos.
6
Aplicar un sistema de control de excepciones para resolver los problemas lógicos de una aplicación web.
Página 3 de 39
Objetos y declaración de clases
Introducción
Las clases y objetos son la base de un paradigma de programación llamado “Orientación a objetos”. PHP
pertenece a ese paradigma de programación y la utilización de las herramientas que nos ofrece este modelo,
resulta imprescindible a la hora de realizar aplicaciones complejas.
Comenzaremos este primer punto del tema explicando brevemente que es la programación orientada a
objetos, aunque cabe apuntar que el dominio de la orientación a objetos requiere de mucha práctica y una alta
base teórica.
La Orientación a Objetos (OO) es un paradigma de programación cuyo dominio pasa por la comprensión de
un extenso marco teórico que no entra en los contenidos de este curso. Aun así, para los alumnos que no
conozcan la programación orientada a objetos, vamos a hacer un pequeño resumen.
La orientación a objetos es una forma de ver las cosas… una forma de entender un problema
identificando las entidades principales que se encuentran en él.
Cada una de estas entidades nos llevará a la creación de una clase y, cada instancia de estas clases, nos llevará
a la creación de objetos.
¿Qué es un objeto?
Entidades Físicas
(Ej.: Vehículo, Casa, Producto)
Entidades Conceptuales
(Ej.: Proceso Químico, Transacción Bancaria)
Página 4 de 39
Entidades de Software
(Ej.: Lista Enlazada, Interfaz Gráfica)
Según Rumbaugh (conocido por su aportación en la creación de la técnica del modelado de objetos), un objeto
se puede definir como: “Un concepto, abstracción o cosa con un significado y límites claros en el problema en
cuestión”
Propiedades en común
atributos
Comportamiento similar
operaciones
Un objeto es una instancia de una clase, por lo que se puede entender como una definición abstracta de un
objeto que define la estructura y el comportamiento compartidos por los objetos y sirve como modelo para la
creación de objetos.
Página 5 de 39
Por ejemplo, tenemos un taller mecánico y vamos a manejar diferentes coches. La abstracción de
características comunes sería “Coche”, por lo que crearíamos dicha clase. Los atributos de esa clase serían:
marca, modelo, año, km, etc…
Cada vez que instanciemos la clase “Coche” obtendremos un objeto con diferente estado (valores de los
atributos).
• Clase Coche
◦ Comportamiento
▪ AgregarReparacion, GenerarInformeMecanico, …
Pero, si en vez de un taller, se tratase de un concesionario ¿sería la misma clase Coche?, y ¿si se tratase de la
empresa del telepeaje? ¿Les interesa tener datos sobre la mecánica o solamente la matrícula y datos del pago?
Efectivamente, la clase ha de adaptarse a las necesidades del problema. Una clase con el mismo nombre
puede ser completamente diferente en un programa u otro. Seleccionar lo relevante y omitir lo superfluo para
un problema en concreto se denomina abstracción y es uno de los pilares de la orientación a objetos.
En PHP una clase se define mediante la palabra reservada class, y las propiedades y métodos mediante el
modificador de visibilidad. Entraremos luego en ello, de momento utilizaremos public.
class Coche{
public $marca;
public $modelo;
public $color;
public $km=0; //Podemos dar valores por defecto
public function agregarReparacion(){
Página 6 de 39
Para crear un objeto debemos instanciar la clase mediante new:
Una vez tenemos creado un objeto podemos acceder a sus propiedades y métodos mediante el operador “->”:
//Modificación
$miCoche->color="azul";
//Lectura
echo "<p>El color del coche es ".$miCoche->color;
Nótese que, cuando utilizamos este operador, las propiedades a las que nos refiramos deberán escribirse
omitiendo el símbolo dollar($). Este símbolo sirve para indicar al intérprete que los próximos caracteres
que se encuentre forman el identificador de una variable, como ya lo establecemos al principio, ya no es
necesario volver a indicarlo justo del nombre del atributo.
Referencias a objetos
En el ejemplo del apartado anterior, vemos como la variable $miCoche “contiene” un objeto de tipo Coche
desde el mismo momento que utilizamos el operador new. Esto no es del todo cierto puesto que desde
la versión 5 de PHP, este tipo de variables que “contienen” objetos se denominan “referencias” y no
contiene al objeto en sí, sino un identificador que sirve para localizar en memoria al objeto real. Esto,
puede resultar difícil de comprender si nunca se programó con lenguajes orientados a objetos, pero en
realidad es una práctica muy habitual que permite trabajar con objetos de una forma muy sencilla.
La principal implicación de esto es que por mucho que asignemos el valor de una referencia a otra, el
objeto final es el mismo puesto que lo único que estamos copiando de una variable a otra es el identificador
que nos permitirá localizarlo.
Página 7 de 39
Vamos a verlo con un ejemplo. Cuando trabajamos con variables normales (tipos simples), el valor de la
variable se copia en cada asignación:
$a=15;
$b=$a;
$a=6;
echo $a; //6
echo $b; //15
En la segunda línea estamos copiando el valor de $a (15) en $b, y ya no volvemos a modificar $b, por lo que
conserva ese valor a pesar de que $a sí que es modificado.
$miCoche2= $miCoche1;
$miCoche2->color="rojo";
La variable $miCoche1 no es modificada explícitamente en todo el bloque de código, sin embargo, su color
pasa a ser de azul a rojo. Esto sucede porque realmente estas variables no almacenan al objeto en sí como si
de un tipo simple se tratara, sino que son referencias al objeto.
Página 8 de 39
Vamos a volver al ejemplo para intentar explicar que es lo que sucede. Como vemos, en todo el bloque de
código solamente hay un new , esto implica que solo tenemos un objeto creado. La asignación $miCoche1=
new Coche(), tan solo guarda una referencia (identificador) del coche que acabamos de crear:
Página 9 de 39
Cuando hacemos la asignación a otra variable, lo que copiamos es el contenido de $miCoche1, es decir la
referencia del objeto, y no hacemos una copia del objeto en sí.
Por eso, si hacemos una modificación utilizando $miCoche2, estaremos modificando el mismo coche que si
modificamos $miCoche1:
Página 10 de 39
El siguiente código define una clase muy simple, denominada “Producto” con tres atributos y una función
mostrar() que genera una cadena de texto con la información del producto en cuestión.
Tras la definición de la clase, se realizan varias sentencias en las que se instancian varios objetos y se modifican
atributos y referencias.
Introducción
En un lenguaje como PHP, casi cualquier cosa es una expresión. Primero trataremos de explicar este
concepto, para después adentrarnos en un tipo de expresión muy especifica de la orientación a objetos, y
son aquellas que inicia un objeto: los constructores.
En PHP además, igual que podemos construir un objeto a partir de una clase, también podemos destruirlo
para liberar recursos y mejorar el rendimiento de la aplicación.
Expresiones
Las expresiones son bloques de construcción, es decir, un código que tras ejecutarse se resuelve en un valor.
Casi todo lo que se escribe en PHP es una expresión, de hecho, se pueden definir de una forma muy sencilla
como “Cualquier cosas que tenga un valor”.
La expresión más simple del lenguaje serían, lógicamente, los literales, es decir, escribir un número cuatro
(4) sería una expresión con valor cuatro (4):
$val=4;
Tras la ejecución de la línea anterior, la variable $val pasaría a ser una expresión con valor cuatro (4), ya que,
efectivamente, las siguientes expresiones en orden de complejidad serían las variables y constantes.
$val=4;
$val2=$val;
En este segundo ejemplo, vemos que si asignamos a una segunda variable el valor de $val, sería lo mismo que
asignarle el valor cuatro.
Página 11 de 39
Unas expresiones un poco más complejas serían las funciones:
function dameUnCuatro(){
return 4
}
Como podemos imaginar en el momento que hagamos una llamada a la función, esa llamada es una expresión
con valor cuatro.
Por supuesto, no es necesario que el valor sea un entero. De hecho, cualquiera de los tipos de datos simples
que vimos en el tema anterior serían validos: enteros, flotantes, cadenas y booleanos. Además, PHP admite dos
tipos complejos (tipos de datos compuestos de varios datos simples): las arrays (matrices) y los objetos.
La propia asignación de un valor también puede considerarse una expresión, ya que se puede sustituir
por un valor. Lo explicamos, en la siguiente sentencia, $val2 pasa a tener valor “Hola”:
$val2=$val=‘Hola’;
Por lo que la asignación $val=‘Hola’, puede sustituirse por “Hola”, así que es una expresión.
Un tipo muy común de expresiones son las que involucran operadores de comparación y cuyo valor
final es un booleano. Estas expresiones suelen utilizarse en el control de bucles y del flujo de ejecución, por
lo que su dominio es muy importante.
Con la intención de repasar el tema anterior, así como de dejar claro el concepto de expresión, os propongo el
siguiente ejercicio:
Completa con los valores que se piden en los comentarios de las siguientes expresiones.
function doble($i)
{
return $i*2;
}
$b = $a = 5; /* $a= $b= */
$c = $a++; /* $a= $c= */
$e = $d = ++$b; /* $b= $d= $e= */
$f = doble($d++); /* $f= $d= */
$g = doble(++$e); /* $g= $e= */
$h = $g += 10; /* $h= y $h= */
Página 12 de 39
SOLUCIÓN:
function doble($i)
{
return $i*2;
}
$b = $a = 5; /* $a=5 $b=5 */
$c = $a++; /* $a=6 $c=5 */
$e = $d = ++$b; /* $b=6 $d=6 $e=6 */
$f = doble($d++); /* $f=12 $d=7 */
$g = doble(++$e); /* $g=14 $e=7 */
$h = $g += 10; /* $h=24 y $g=24 */
Constructores
Los constructores son unos métodos especiales y exclusivos de las clases que especifican cómo se debe
crear un objeto.
Estos métodos son invocados en el momento en el que hacemos un “new”, esa es la razón de que cuando
hacemos $miCoche= new Coche(), ponemos los paréntesis de la ejecución de un método.
Cuando, como hasta ahora, no tenemos especificado un constructor, cada vez que hacemos un “new”, se
invoca al constructor por defecto. Este es un método oculto que se crea con cada clase y que se limita a
reservar la memoria necesaria para el objeto e iniciar sus atributos con los valores por defecto.
class Coche{
…
public function __construct($matricula){
$this->matricula=$matricula;
}
…
}
Como vemos, para que se identifique como constructor, debemos de nombrarlo con la palabra “construct”
precedida de dos guiones bajos (__).
Página 13 de 39
Destructores
A partir de la versión 5, PHP incorpora este concepto ampliamente utilizado en otros lenguajes orientados a
objetos. Cabe destacar que la liberación de memoria en PHP es automática y que, a pesar de lo que su nombre
pueda aparentar, el destructor no se le llama cuando se quiera eliminar el objeto.
PHP, al igual que muchos otros lenguajes orientados a objetos, elimina un objeto de la memoria cuando este
se queda sin referencias. Es aquí cuando el destructor es llamado automáticamente. Por ello, podríamos
definir a los destructores de PHP no como a funciones que destruyen objetos, sino como funciones que se
invocan cuando un objeto es destruido.
El objetivo suele ser eliminar recursos asociados al objeto que se acaba de eliminar como, por ejemplo, cuando
se trabaja con bases de datos. Es muy común que el fin de la utilización de un objeto en una aplicación web, se
traduzca en una eliminación o inserción en la base de datos.
class Coche{
…
public function __destruct(){
echo “Eliminado el coche ”.$this->$matricula;
}
…
}
De forma similar al constructor, debemos de nombrarlo con la palabra “destruct” precedida de dos guiones
bajos (__).
Hasta este momento hemos definido los métodos y atributos mediante public. Este modificador, indica que
pueden ser accedidos desde afuera de la clase. De esta forma, podríamos hacer:
$miCoche->color="azul";
El problema es que los atributos se consideran parte del funcionamiento interno de la clase y no
deberían ser accesibles desde afuera. Los métodos, en cambio, los hay que si deberían ser públicos (los
servicios que realmente ofrece esa clase al programa) y otros que solo son de uso interno. Para ello se
definen otras dos visibilidades:
Private
No puede verse o modificarse a no ser que sea desde la propia clase.
Protected
No puede verse o modificarse a no ser que sea desde la propia clase o desde clases que hereden de ella (Se
verá la herencia en el punto siguiente).
Página 14 de 39
La norma general para los atributos es ponerlos privados, y los que queramos que sean legibles y/o
modificables, les haremos métodos de acceso. Los métodos de acceso, por convenio, comienzan con la
palabra “get” o “set” seguida por el nombre del atributo. Imaginemos que queremos crear un atributo
matrícula. Esta, obviamente, no se puede modificar, pero queremos permitir su lectura:
class Coche{
private $matricula;
…
public function getMatricula(){
return $matricula;
}
}
Ahora pensemos en el atributo color. El coche puede repintarse, por lo que queremos permitir la modificación
de ese dato. Entonces haremos los dos métodos de acceso:
class Coche{
private $color;
…
public function getColor(){
return $color;
}
public function setColor($nuevoColor){
$color=$nuevoColor;
}
…
}
}
En este ejemplo, al recibir un nuevo color, evitamos llamar al parámetro $color para que no entre en conflicto
con el atributo. Pero la forma correcta de evitarlo es mediante el uso de la variable $this.
Página 15 de 39
La variable $this se puede utilizar en cualquier método y hace referencia al propio objeto que hemos
instanciado:
class Coche{
private $color;
…
public function getColor(){
return $this->$color;
}
public function setColor($color){
$this->$color=$color;
}
…
}
Esta variable nos permite, por ejemplo, hacer comparaciones entre dos objetos. Vamos a crear un método
que nos diga si el coche tiene más potencia que otro coche que reciba como parámetro:
class Coche{
private $potencia;
public function getPotencia(){
return $this->$potencia;
}
public function masPotenteQue($otroCoche){
return $this->$potencia>$otroCoche->getPotencia();
}
…
}
Reescribe la clase Producto del primer ejercicio de autoevaluación que te propusimos, para que sea
consecuente con lo explicado en esta sección, de forma que se consiga una encapsulación correcta. Añade
también un constructor que asigne valores iniciales a cada producto.
Te recordamos el script:
SOLUCIÓN:
Página 16 de 39
Herencia en PHP
1
Implementación de la herencia
2
Referencias y herencia
3
Inclusión del modelo en archivos externos
1. Implementación de la herencia
La idea es la de partir de situaciones más generales e ir derivando hacia las más particulares,
estableciendo una jerarquía de clases en forma de árbol. No se debe utilizar como una forma de ahorrarnos
código, sino como una herramienta para que nuestra abstracción se parezca más a la realidad.
Imaginemos que nuestro taller mecánico también acepta motos. Teniendo en cuenta que varios atributos y
métodos son comunes, lo que debemos de hacer es una abstracción superior que llamaremos Vehiculo y de la
que extenderán Coche y Moto. En Vehiculo pondremos todos los atributos y métodos comunes entre las clases
que heredan de ella, y en dichas clases nos limitaremos a poner los atributos y métodos exclusivos de cada
una de ellas.
Al especificar que Coche y Moto heredan de Vehículo, automáticamente podremos utilizar todas las propiedades
y métodos de Vehiculo como si fueran de ellas.
Página 17 de 39
En PHP la herencia se especifica en las clases hijas, mediante el modificador extends seguido del nombre de
la clase padre.
class Vehiculo{
private $marca;
private $modelo;
private $color;
private $km=0; //Podemos dar valores por defecto
…
//Resto de funciones
public function agregarReparacion(){
//Contenido del método
}
}
Página 18 de 39
2. Referencias y herencia
Los lenguajes con tipado dinámico como PHP, como vimos, no necesitan establecer tampoco el nombre
de la clase a la que se va a referenciar en una variable. Al igual que con un tipo simple, la propia asignación
es suficiente para adaptar la referencia al tipo de objeto que le asignemos. De esta forma si hacemos
$miCoche = new Coche(), la variable $miCoche pasa a ser automáticamente de tipo Coche.
Esto, que puede parecer una ventaja ya que facilita la programación, en algunos casos se traduce en un
pobre control de la situación, y fuente común de errores en el paso de parámetros. Veamos un ejemplo,
supongamos que creamos una función para pintar coches:
Podemos hacer una llamada a pintar pasando como parámetro algo que no sea un coche, ya que, al haber
tipado dinámico, el parámetro $coche se convertirá al tipo adecuado. Si invocamos a la función mediante, por
ejemplo pintar(new Lampara(), “Rojo”) no habría ningún error en la llamada, pero en el momento del cambio
de color, no encontrará ese parámetro en la clase Lampara.
PHP ofrece un mecanismo mediante el cual podemos obligar a que un determinado parámetro albergue
siempre referencias de una determinada clase. Así podríamos definir el método anterior para que
solamente aceptase objetos de tipo Coche:
La herencia nos permite también que un parámetro definido como referencia de una clase A, padre de B,
pueda referenciar objetos tanto de clase A, como B, como de cualquier otra clase que descienda de ellas
en la jerarquía.
Página 19 de 39
Esto es debido a que se cumple la regla básica de la herencia, la regla “..es un..”. Siempre que existe
herencia entre A y B, es porque se puede aplicar la regla “B es un A”, y por tanto podremos utilizar una
referencia de A para albergar objetos B. Por ejemplo, “Coche es un Vehiculo”, lo que implica que podremos
usar referencias de tipo Vehiculo para referenciar Coches. Pero ¡ojo! esto solo se cumple en un sentido, si nos
preguntamos “Vehiculo es un Coche” la respuesta claramente es no, por lo que nunca podremos utilizar una
referencia de tipo Coche para referenciar a objetos de tipo Vehiculo.
Esto sucede, porque se supone que si Coche hereda de Vehículo, es porque se presupone que tiene una
estructura común, y por tanto, habrá ocasiones en las que se puedan utilizar indistintamente (al igual que el
resto de clases de la jerarquía). Si en el ejemplo anterior establecemos que solamente podemos pintar coches
(del tipo que sean), y no ningún otro tipo de vehículo, haríamos:
Reforma la clase Producto, que trabajamos en los ejercicios de autoevaluación anteriores, para que se convierta
en la clase padre de Libro, Pelicula y Revista. Crea, por lo menos, un atributo específico de cada una de las clases
hijas.
SOLUCIÓN:
Página 20 de 39
3. Inclusión del modelo en archivos externos
La organización del código es algo fundamental para que nuestras aplicaciones sean comprensibles y
fáciles de mantener. En el próximo tema abordaremos un patrón de diseño llamado MVC (Model-View-
Controller) que pretende separar la lógica de la aplicación (Controller), la parte visual (view) y el modelo de
clases (model). Para ir acostumbrándonos a agrupar código, explicaremos como aislar el modelo de clases del
resto de la aplicación, y así poder referenciarlo en diferentes páginas.
PHP incluye una instrucción “include”. Mediante la misma, podemos insertar el código de una página PHP en
el punto exacto donde pongamos esa instrucción. Veamos un ejemplo:
Archivo: modelo.php
< ?php
class Vehiculo{
…
}
class Coche extends Vehiculo{
…
}
class Avion extends Vehiculo{
…
}
class Tractor extends Vehiculo{
…
}
?>
En el documento anterior vemos como se definen las clases del modelado del problema. Es importante que
este documento no tenga HTML y empiece y termine por las marcas de bloque de PHP. El código tal cual
será insertando en el momento en que hagamos un include:
…
include ‘modelo.php’;
$miCoche= new Coche(); //Ya podemos utilizar las clases
De esta forma tan simple podemos separar el modelo del resto de la aplicación e incluirla en las páginas
donde sea necesario trabajar con alguna clase. Cabe decir que la instrucción “include” no es específica para
aislar el modelo, sino que cualquier código PHP puede ser incluido en otro utilizando dicha instrucción. En
muchas ocasiones se utiliza tambien para crear una colección de funciones en un fichero de utilidades.
Página 21 de 39
Operadores y polimorfismo
El polimorfismo, como su nombre indica, se refiere a la capacidad de tener múltiples formas. Cuando en
programación utilizamos este término, nos referimos a que un mismo identificador o función pueda tener
diferentes comportamientos en función al contexto en el que se ejecutan. Se trata de uno de los pilares
fundamentales de la orientación a objetos junto a la encapsulación y a la herencia.
En lenguajes fuertemente tipados, es decir, en los que estamos obligados a definir el tipo de cada variable (o
referencia) debemos hacer uso de lo explicado en el punto 2 (Expresiones, Constructores y Destructores) para
poner en práctica el polimorfismo. Veamos un ejemplo, primero definimos la jerarquía de clases:
class Vehiculo{
function arrancar(){
echo “Arranca diferente dependiendo del tipo de Vehiculo”;
Página 22 de 39
}
}
class Coche extends Vehiculo{
function arrancar(){
echo “Brruummmmm!”;
}
}
class Avion extends Vehiculo{
function arrancar(){
echo “Miiiiiiuu!”;
}
}
class Tractor extends Vehiculo{
function arrancar(){
echo “Trrruuuuu!”;
}
}
Página 23 de 39
Creamos entonces una función que recibe un objeto de tipo Vehiculo (que puede ser también un coche, avión
o tractor) y se limita a utilizar su método arracar(). Aquí es donde se hace la “magia” del polimorfismo; tenemos
un Vehiculo que a priori no sabemos de qué tipo es, sin embargo, el sistema es capaz de reconocerlo y
ejecutar la versión oportuna del método.
La salida, será:
Página 24 de 39
Cómo ya explicamos previamente, PHP es un lenguaje con tipado dinámico y no necesita especificar un tipo
de referencia en los parámetros ya que es capaz de adaptarse dinámicamente al tipo de referencia que se
le asigne. Esto complica un poco la comprensión del polimorfismo, puesto que un ejemplo como el siguiente,
también funcionaría:
class Coche{
function arrancar(){
echo“Brruummmmm!”;
}
}
class Avion{
function arrancar(){
echo“Miiiiiiuu!”;
}
}
class Tractor{
function arrancar(){
echo“Trrruuuuu!”;
}
}
function arrancar($obj)
{
$obj ->arrancar();
}
arrancar($coche);
arrancar($avion);
arrancar($tractor);
Aunque el código pueda parecer más sencillo, la no necesidad de realizar una jerarquía que vincule a las
tres clases desvirtúa el polimorfismo, además de ser una fuente habitual de errores. Por ello, y con vistas
a reutilizar conocimientos en otros lenguajes de programación, se recomienda utilizar siempre que sea posible
la primera opción creando una jerarquía de clases y vinculando el polimorfismo a la herencia.
Reimplementa el método mostrar en Libro, Película y Revista (de los anteriores ejercicios) y realizar llamadas
polimórficas para comprobar que efectivamente se invoca al método adecuado.
SOLUCIÓN:
Página 25 de 39
Métodos y clases abstractas
Las clases abstractas son clases que no se instancian y solo tienen como objetivo atributos y métodos
que puedan ser heredados, trasladando así un funcionamiento obligatorio a clases hijas. Mejoran la calidad
del código y ayudan a reducir la cantidad de código duplicado.
Un buen ejemplo, sería el método arrancar del ejemplo anterior. En ningún caso nos interesa arrancar un
“vehiculo”, lo que arrancaremos será un coche, un avión o un tractor. El hecho de especificar en la clase
Vehiculo el método “arrancar” es porque queremos dejar constancia de que todos los vehículos deben poder
arrancar, aunque cada uno lo haga de forma diferente.
class Vehiculo{
Una clase abstracta es la que contiene algún método abstracto. No es necesario que todos los métodos lo
sean, pero con tener uno sin cuerpo ya no tiene sentido poder crear instancias y por eso debemos definir
la clase como abstracta. Si una clase con métodos abstractos no la definimos como tal, el sistema nos
notificará un error:
Una clase abstracta se define de la misma manera que un método: anteponiendo la palabra reservada
“abstract”:
Página 26 de 39
En el momento que cualquier clase herede de una clase abstracta se verá obligada a implementar un
comportamiento a los métodos abstractos, mientras que los métodos que no lo sean, así como las
propiedades, se heredarán directamente.
class Coche{
Que nos viene a decir que estamos obligados a implementarlo o volver a definirlo como abstracto. Si
hiciéramos lo segundo, la clase coche también debería ser abstracta.
Página 27 de 39
Veamos el ejemplo completo utilizando clases abstractas:
$matricula=0;
function setMatricula($matricula){
this->matricula=$matricula;
}
abstract function arrancar();
abstract function presentarse();
}
class Coche extends Vehiculo{
function arrancar(){
echo“Brruummmmm!”;
}
function presentarse(){
echo“Hola, soy un coche con matricula ”. this->matricula;
}
}
class Avion extends Vehiculo{
function arrancar(){
echo“Miiiiiiuu!”;
}
}
function presentarse(){
echo“Hola, soy un avión con matricula ”. this->matricula;
}
}
Se ha añadido a la clase abstracta un método y atributo no abstractos. Estos se heredan con normalidad,
por lo que, aunque no exista referencia de ellos en las clases hijas, podremos hacer esto sin inconvenientes:
La clase Producto de los ejercicios anteriores, es un claro ejemplo de clase abstracta. Utiliza correctamente los
métodos abstractos para convertir la clase Producto en abstracta.
SOLUCIÓN: Con poner abstracto al método mostrar(), y añadir “abstract” a la clase Producto, bastaría.
Página 28 de 39
Interfaces y herencia de interfaces
¿Qué es un Interface?
Para comprender que es un interface, se suele recurrir al símil de un contrato; un contrato de cualquier clase
que lo firme estará obligada a cumplir. En él se definen solamente métodos vacíos que las clases que
implementen el interface deberán cumplir. Nos sirven para designar obligaciones, organizar el código y
hacer más intuitivo y reconocible el código. En cuanto veamos que una clase implementa ciertos interfaces,
ya sabremos que cumple ciertas funcionalidades.
La idea es similar al de las clases y métodos abstractos, pero tenemos varias diferencias. La principal es que
para implementar un interface no es necesaria una relación semántica entre ambas clases (y por supuesto,
si la hubiera, nunca será de herencia). Por otro lado, los interfaces solo declaran métodos públicos, puesto
que se trata de una “promesa de funcionalidad”: la clase que implementa un interface deberá ofrecer ciertas
funcionalidades, pero cómo lo consiga depende del programador.
Página 29 de 39
Uso de Interfaces en PHP
Un interface se crea como una clase, pero utilizando la palabra reservada “interface” en lugar de “class”.
Posteriormente, las clases que implementen un interface (no se dice heredar ni extender), lo harán
mediante la palabra reservada “implements”. Una clase podrá implementar varios interfaces.
interface Arrancable{
public function arrancar();
}
En el ejemplo anterior tenemos el interface “Arrancable” que obliga a que las clases que lo implementen
ofrezcan la funcionalidad de “arrancar”. ¿Qué diferencia hay con la clase abstracta “Vehiculo”? Pues que
en una relación de herencia se precisa de que exista una relación semántica padre-hijo entre ambas
clases (Coche ES UN Vehiculo). La propia definición de herencia nos impediría extender de Vehiculo una
clase Ordenador, puesto que semánticamente no tienen una relación padre-hijo. En cambio, mediante un
interface “Arrancable”, podemos implementar esa funcionalidad en cualquier clase que creamos que
deba cumplirla, desde un coche a un ordenador.
Si nos fijamos en el método arrancar de la clase ordenador, podemos comprobar como se llama a dos
funciones privadas para cumplir su misión.
Página 30 de 39
Implementando varios interfaces
Una clase puede implementar tantos interfaces como sea necesario. Como decíamos, no hay una
vinculación semántica entre ellos, y simplemente son diferentes contratos que la clase debe asumir. La forma
de conseguirlo es especificando la lista de interfaces implementados separados por comas (,).
Imaginemos que tenemos un interface Arrancable y otro Apagable. Si queremos especificar que una clase se
puede arrancar y apagar, podríamos hacer lo siguiente:
interface Arrancable{
public function arrancar();
}
interface Apagable{
public function apagar();
}
...
}
Herencia de Interfaces
Los interfaces pueden heredarse exactamente igual que si se tratase de clases. En este caso, la herencia
es mucho más sencilla que en clases, puesto que como un interface solamente contiene métodos públicos
sin definición, la herencia se limita a copiar las definiciones de métodos de la clase padre a la hija.
Siguiendo con el ejemplo del punto anterior, y bajo el supuesto de que cualquier cosa que se pueda apagar es
porque también puede encenderse, podemos hacer lo siguiente:
interface Arrancable{
public function arrancar();
}
interface Apagable extends Arrancable {
public function apagar();
}
class Coche implements Apagable {
public function arrancar(){
...
}
public function apagar(){
...
}
...
}
Página 31 de 39
Crea el interface “Alquilable” con métodos “Alquilar” y “Devolver”. Los libros y películas deberán adaptarse a
este interface, mientras que las revistas no son alquilables.
En base a todo lo que vimos de orientación a objetos hasta ahora, ¿qué decisión de diseño crees que
podríamos tomar para implementar la solución de una manera correcta?
SOLUCIÓN:
La forma más correcta sería crear una clase “ProductoAlquilable” que heredase directamente de Producto e
implementase el interfaz “Alquilable”, de esta forma, las dos clases hijas de “ProductoAlquilable”, heredarían la
misma versión de los métodos. Además, podríamos definir en esa clase atributos y funciones privadas extra
que necesitásemos para realizar la función del interface.
Tratamiento de excepciones
Introducción
Las excepciones es un método muy común y sencillo para detectar errores en la lógica de nuestra
aplicación y asociar a cada uno un código de tratamiento del error. De esta forma, no solo se ejecuta dicho
código, sino que también se saltan las líneas de código críticas donde el acarreo del error podría llevar a
nuevos errores o valores incorrectos.
Primero, hablaremos de los tipos de errores y mensajes que podemos obtener directamente en PHP.
Posteriormente, entraremos en la gestión mediante excepciones.
En PHP podemos ocultar o mostrar los diferentes tipos de errores que pueden ocurrir. Debido a que se
trata de un lenguaje interpretado, el programador no dispone de la misma información acerca de los errores
que en un lenguaje compilado. Cuando se crea un programa con un lenguaje compilado, el propio proceso
de compilación realiza un análisis del código y cuando se detecta un fallo, el código no llega a compilar y
por tanto a ejecutarse.
En cambio, en los lenguajes interpretados, al no existir un proceso de compilación, los errores se detectan
durante la ejecución (el programa no funciona o lo hace mal). Esto, si encima no recibimos como
programadores la información correcta, puede convertirse en un importante problema para el desarrollador.
Una web en explotación no debería revelar más información de la cuenta a los usuarios de la misma.
Mensajes y códigos de error dirigidos al programador, nunca deberían mostrarse al usuario de la página. Por
esta razón, los servidores PHP suelen tener desactivada la opción de mostrar mensaje, pero durante el proceso
de desarrollo, podemos activarla para intentar detectar más rápidamente la fuente de nuestros errores.
En PHP existen diferentes tipos de mensajes y errores cuando algo falla en el código en tiempo de ejecución.
Existen hasta 3 niveles de mensajes:
Notificaciones
No son errores necesariamente, pero PHP nos avisa de las partes donde puede haber un error. Un ejemplo
Página 32 de 39
típico de notificación es el intentar acceder a un índice de un array que no existe.
Advertencias
Son errores, pero no con mucha relevancia. En muchos casos, el código podría continuar ejecutándose
a pesar de la advertencia, pero podría dar lugar a valores incorrectos. Por ejemplo, llamar a una función
con un numero diferente de parámetros genera una advertencia.
Errores
Son errores relevantes y los cuales debemos corregir de manera inmediata ya que detendrán la ejecución
de nuestro código y no nos permitirán continuar.
Realmente hay más categorías en PHP, pero con estas tres son las más relevantes y nos darán toda la
información necesaria.
En la carpeta de instalación de Xampp, tenemos una carpeta “php” que incluye los archivos necesarios para que
funcione el módulo de PHP en el servidor. Dentro de esta carpeta se encuentra una serie de archivos editables
que nos permiten configurar diferentes aspectos del interprete PHP.
error_reporting
Esta opción es la que nos permitirá definir qué errores queremos mostrar en nuestro servidor. Los
posibles valores, se nos muestran comentados en las líneas anteriores. Entre ellos, reconoceremos los tres
niveles de errores a los que nos referíamos:
E_NOTICE
Notificaciones
E_WARNING
Advertencias
E_ERROR
Errores
E_ALL
Mostrar todo tipo de errores y mensajes
Debemos tener en cuenta que podemos hacer combinaciones entre ellos, mediante los operadores lógicos
& (y) y ~ (negación). Por ejemplo, la siguiente línea mostrará todos los avisos excepto las notificaciones:
Página 33 de 39
Función error_reporting()
Si no queremos modificar el archivo php.ini, también podemos hacer uso de la función error_reporting(), la
cual permite escoger el nivel de notificaciones que queremos mostrar. Para ello, debemos establecerlo
al principio de la página:
Hay errores que pueden ocurrir durante la ejecución de un programa que no son evitables (normalmente
asociados a valores externos o introducidos por el usuario). En estos casos, el programador debe preverlos
y establecer un comportamiento que se ejecutará solo en el caso de que se produzca el error.
PHP, al igual que muchos otros lenguajes de programación, solventa esto gracias a las excepciones. Los
lenguajes que tienen control de errores mediante excepciones se basan en tres pasos muy sencillos:
1
Detectamos en qué líneas se puede producir un error y las marcamos dentro de un bloque “try”.
Especificamos que esas líneas deben “intentarse”.
2
Como programadores, debemos codificar la detección del error antes de que este se produzca. En ese
momento lanzamos la excepción.
3
Establecemos un código con un tratamiento del error en otro bloque que llamaremos “catch”. Será donde
capturemos la excepción y le demos solución.
La idea es que, si se produce un error dentro de un bloque “try”, la ejecución salta directamente al bloque
“catch” asociado, saltándose todo el código restante para evitar que se siga trabajando con valores incorrectos.
Página 34 de 39
Lanzando una excepción
PHP incorpora la interfaz Throwable que incorpora varios errores (lanzan automáticamente una excepción)
y excepciones que podemos lanzar:
Error
ArithmeticError
DivisionByZeroError
AssertionError
ParseError
TypeError
ArgumentCountError
Exception
ClosedGeneratorException
DOMException
ErrorException
IntlException
LogicException
BadFunctionCallException
BadMethodCallException
DomainException
InvalidArgumentException
LengthException
OutOfRangeException
PharException
ReflectionException
RuntimeException
OutOfBoundsException
OverflowException
PDOException
RangeException
UnderflowException
UnexpectedValueException
SodiumException
Página 35 de 39
Para lanzar una excepción, debemos utilizar la palabra reservada throw seguida por la creación de una
nueva instancia de la clase oportuna. Un error muy típico es la división entre cero. Veamos un ejemplo:
class Pruebas
{
}catch(DivisionByZeroError $e){
echo $e->getMessage();
}
En este código, se llama a una función en la que detectamos que puede haber una división entre cero. Al ser
este un error previsible, forma parte de la lista de errores y excepciones predefinidas que podemos utilizar.
En cuanto detectamos que se va a realizar la división entre cero, lanzamos la excepción, cuyo constructor
acepta como parámetro un mensaje de error. En ese mismo momento ya no se ejecuta nada más, se sale de
la función al punto desde donde se llamó y se saltan las líneas restantes hasta el bloque catch donde le damos
una solución.
Página 36 de 39
En este ejemplo tan simple, la solución que le damos es simplemente mostrar el mensaje de error (y, sobre
todo, el habernos saltado las líneas anteriores donde se usaría un valor erróneo).
}catch(InvalidArgumentException $e){
echo $e->getMessage();
}
En este ejemplo, recibimos mediante POST un valor que se había especificado que debe de estar entre 0
y 9. Obviamente, si se trata de una restricción de la lógica de nuestro programa, PHP no puede detectar
automáticamente nada extraño. En este caso, solamente si la lanzamos nosotros como en el ejemplo la
podremos interceptar. Como vemos, utilizamos un InvalidArgumentException , siempre debemos buscar la
clase que mejor se adapte a nuestro problema. No hay diferencias entre el comportamiento de una u otra,
pero siempre quedará mejor descrito el error si utilizamos una cuyo nombre se adapte al error que se produjo.
Página 37 de 39
Creación de excepciones
getMessage()
devuelve el mensaje de la excepción
getCode()
devuelve el código del error
getFile()
devuelve el nombre del fichero que lanzó la excepción
getLine()
devuelve el la línea del fichero que lanzó la excepción
getTrace()
devuelve la pila de ejecución en formato de array
getTraceAsString()
devuelve la pila de ejecución en formato de string
Hay veces que queremos contemplar una situación muy concreta y que ninguna de las clases que nos ofrece
PHP se adapta al 100% al error que queremos describir. En estos casos tan solo debemos crear una clase que
herede de Exception. De esta forma, heredaremos todos los métodos listados que acabamos de describir y
podemos utilizarla exactamente igual que las excepciones predefinidas.
Además, como cualquier clase que hereda de otra, tenemos la opción de reimplementar cualquiera de estos
métodos si queremos, por ejemplo, adaptar el mensaje por defecto.
Página 38 de 39
Controlando varias excepciones
Muchas veces, en una misma operación se pueden producir varias excepciones. Es un error bastante común
intentar poner un bloque try por cada posible excepción. Esto nunca debe de hacerse, pues un mismo
bloque try puede tener múltiples catch, manejando cada uno de ellos una excepción concreta:
try
{
…
}catch(InvalidArgumentException $e){
echo $e->getMessage();
}catch(LengthException $e){
echo $e->getMessage();
} catch(Exception $e){
echo “Error no identificado”;
}
En el bloque try del ejemplo, vamos a imaginar que pueden producirse dos tipos distintos de excepciones:
InvalidArgumentException y LengthException. Si en algún momento de dicho código se produce alguna
de estas excepciones, se saltará únicamente al bloque adecuado. En este ejemplo, en ambos bloques nos
limitamos a hacer lo mismo, mostrar el error, pero al diferenciar entre ambos tipos, el error será específico de
cada error.
A veces, el código es largo y puede producirse otro tipo de errores, por lo que es común utilizar en los
bloques catch directamente la clase Exception. Al ser la clase padre de todas las excepciones, la podemos
utilizar como comodín, ya que cualquier excepción “encaja” en ese bloque catch debido a que cada excepción
solo puede ejecutar un único bloque catch, poniéndolo como última opción solamente en el caso de que la
excepción no concuerde con ninguna otra especificada, se ejecutará este bloque.
Página 39 de 39