"; $mijuego2 = new juego("GP Motoracer", 27, 3, "Playstation II",1,2); echo "" . $mijuego2->titulo . ""; $mijuego2->imprime_jugadores_posibles();
Este código que utiliza la clase "juego" dará como salida: Juego para: Playstation Final Fantasy 2.5 (IVA no incluido) Para un jugador Para un jugador GP Motoracer De 1 a 2 Jugadores.
Manual de PHP 5 - Manual completo
Página 18 de 36
Los atributos de los objetos pueden ser otros objetos Las características de los objetos, que se almacenan por medio de los llamados atributos o propiedades, pueden ser de diversa naturaleza. La clase hombre puede tener distintos tipos de atributos, como la edad (numérico), el nombre propio (tipo cadena de caracteres), color de piel (que puede ser un tipo cadena de caracteres o tipo enumerado, que es una especie de variable que sólo puede tomar unos pocos valores posibles). También puede tener una estatura o un peso (que podrían ser de tipo float o número en coma flotante). En general, podemos utilizar cualquier tipo para los atributos de los objetos, incluso podemos utilizar otros objetos. Por ejemplo, podríamos definir como atributo de la clase hombre sus manos. Dada la complejidad de las manos, estas podrían definirse como otro objeto. Por ejemplo, las manos tendrían como características la longitud de los dedos, un coeficiente de elasticidad. Como funcionalidades o métodos, podríamos definir agarrar algo, soltarlo, pegar una bofetada, o cortarse las uñas. Así pues, uno de los atributos de la clase hombre podría ser un nuevo objeto, con su propias características y funcionalidades. La complejidad de las manos no le importa al desarrollador de la clase hombre, por el principio de encapsulación, dado que este conoce sus propiedades (o aquellas declaradas como public) y los métodos (también los que se hayan decidido declarar como públicos) y no necesita preocuparse sobre cómo se han codificado. Clase cliente del videoclub Para continuar el ejemplo del videoclub, hemos creado la clase cliente que vamos a explicar a continuación. En los clientes hemos definido como atributo, entre otros, las películas o juegos alquilados. Nota:Como vemos, los objetos pueden tener algunos atributos también de tipo objeto. En ese caso pueden haber distintos tipos de relaciones entre objetos. Por ejemplo, por pertenencia, como en el caso de la clase hombre y sus manos, pues a un hombre le pertenecen sus manos. También se pueden relacionar los objetos por asociación, como es el caso de los clientes y las películas que alquilan, pues en ese caso un cliente no tiene una película propiamente dicha, sino que se asocia con una película momentáneamente.
La clase cliente que hemos creado tiene cierta complejidad, esperamos que no sea demasiada para que se pueda entender fácilmente. La explicaremos poco a poco para facilitar las cosas. Atributos de la clase cliente Hemos definido una serie de atributos para trabajar con los clientes. Tenemos los siguientes: public $nombre; private $numero; private $soportes_alquilados; private $num_soportes_alquilados; private $max_alquiler_concurrente;
Como se puede ver, se han definido casi todos los atributos como private, con lo que sólo se podrán acceder dentro del código de la clase. El atributo nombre, que guarda el nombre propio del cliente, es el único que hemos dejado como público y que por tanto se podrá referenciar desde cualquier parte del programa, incluso desde otras clases. El atributo numero se utiliza para guardar el identificador numérico del cliente. Por su parte, soportes alquilados nos servirá para asociar al cliente las películas o juegos cuando este las alquile. El atributo num_soportes_alquilados almacenará el número de películas o juegos que un cliente tiene alquilados en todo momento. Por último, max_alquiler_concurrente indica el número máximo de soportes que puede tener alquilados un cliente en un mismo instante, no permitiéndose alquilar a ese cliente, a la vez, más que ese número de películas o juegos.
Manual de PHP 5 - Manual completo
Página 19 de 36
El único atributo sobre el que merece la pena llamar la atención es soportes_alquilados, que contendrá un array de soportes. En cada casilla del array se introducirán las películas o juegos que un cliente vaya alquilando, para asociar esos soportes al cliente que las alquiló. El array contendrá tantas casillas como el max_alquiler_concurrente, puesto que no tiene sentido asignar mayor espacio al array del que se va a utilizar. Para facilitar las cosas, cuando un cliente no tiene alquilado nada, tendrá el valor null en las casillas del array. Nota:Recordemos que los soportes fueron definidos en capítulos anteriores de este manual de PHP 5 [http://www.desarrolloweb.com/manuales/58/], mediante un mecanismo de herencia. Soporte era una clase de la que heredaban las películas en DVD, las cintas de vídeo y los juegos.
Constructor de la clase cliente function __construct($nombre,$numero,$max_alquiler_concurrente=3){ $this->nombre=$nombre; $this->numero=$numero; $this->soportes_alquilados=array(); $this->num_soportes_alquilados=0; $this->max_alquiler_concurrente = $max_alquiler_concurrente; //inicializo las casillas del array de alquiler a "null" //un valor "null" quiere decir que el no hay alquiler en esa casilla for ($i=0;$isoportes_alquilados[$i]=null; } }
El constructor de la clase cliente recibe los datos para inicializar el objeto. Estos son $nombre, $numero y $max_alquiler_concurrente. Si nos fijamos, se ha definido por defecto a 3 el número máximo de alquileres que puede tener un cliente, de modo que, en el caso de que la llamada al constructor no envíe el parámetro $max_alquiler_concurrente se asumirá el valor 3. El atributo soportes_alquilados, como habíamos adelantado, será un array que tendrá tantas casillas como el máximo de alquileres concurrentes. En las últimas líneas se inicializan a null el contenido de las casillas del array.
Los atributos de los objetos pueden ser otros objetos, 2º parte Método dame_numero() function dame_numero(){ return $this->numero; }
Este método simplemente devuelve el numero de identificación del cliente. Como se ha definido el atributo numero como private, desde fuera del código de la clase, sólo se podrá acceder a este a través del método dame_numero(). Método tiene_alquilado($soporte) function tiene_alquilado($soporte){ for ($i=0;$imax_alquiler_concurrente;$i++){ if (!is_null($this->soportes_alquilados[$i])){ if ($this->soportes_alquilados[$i]->dame_numero_identificacion() == $soporte->dame_numero_identificacion()){ return true; } } } //si estoy aqui es que no tiene alquilado ese soporte return false; }
Este recibe un soporte y devuelve true si está entre los alquileres del cliente. Devuelve false en caso contrario.
Manual de PHP 5 - Manual completo
Página 20 de 36
A este método lo llamamos desde dentro de la clase cliente, en la codificación de otro método. Podríamos haber definido entonces el método como private, si pensásemos que sólo lo vamos a utilizar desde dentro de esta clase. En este caso lo hemos definido como public (el modificador por defecto) porque pensamos que puede ser útil para otras partes del programa. Este método recibe un soporte (cualquier tipo de soporte, tanto cintas de vídeo, como DVDs o juegos). Realiza un recorrido por el array de soportes alquilados preguntando a cada soporte que tenga alquilado el cliente si su número de identificación es igual que el del soporte recibido por parámetro. Como el número de identificación del soporte está definido como private en la clase soporte, para acceder a su valor tenemos que utilizar el método de soporte dame_numero_identificación(). Otra cosa importante. Como no es seguro que en el array de soportes alquilados haya algún soporte (recordamos que si el cliente no tiene nada alquilado las casillas están a null), antes de llamar a ningún método del soporte debemos comprobar que realmente existe. Esto se hace con la función is_null() a la que le enviamos la casilla del array donde queremos comprobar si existe un soporte. Si la función is_null() devuelve true es que tiene almacenado el valor null, con lo que sabremos que no hay soporte. De manera contraria, si la casilla almacena un soporte, la función is_null() devolverá false. Método alquila($soporte) function alquila($soporte){ if ($this->tiene_alquilado($soporte)){ echo "
El cliente ya tiene alquilado el soporte " . $soporte->titulo . ""; }elseif ($this->num_soportes_alquilados==$this->max_alquiler_concurrente){ echo "
Este cliente tiene " . $this->num_soportes_alquilados . " elementos alquilados. "; echo "No puede alquilar más en este videoclub hasta que no devuelva algo"; }else{ //miro en el array a ver donde tengo sitio para meter el soporte $cont = 0; while (!is_null($this->soportes_alquilados[$cont])){ $cont++; } $this->soportes_alquilados[$cont]=$soporte; $this->num_soportes_alquilados++; echo "
Alquilado soporte a: " . $this->nombre . "
"; $soporte->imprime_caracteristicas(); } }
Este método sirve para alquilar una película o juego por parte del cliente. Recibe el soporte a alquilar y, en caso que el alquiler se pueda producir, debe introducir el objeto soporte recibido en el array de soportes alquilados del cliente. Lo primero que hace es comprobar que el cliente no tiene alquilado ese mismo soporte, utilizando el método tiene_alquilado() de la clase soporte. Si no lo tiene alquilado comprueba que todavía tiene capacidad para alquilar otro soporte, es decir, que no ha llegado al máximo en el número de soportes alquilados. Si se puede alquilar el soporte, lo introduce dentro del array soportes_alquilados en una posición vacía (una casilla donde antes hubiera un null), incrementa en uno el número de soportes alquilados e imprime las características del soporte que se ha alquilado. Método devuelve($identificador_soporte) function devuelve($identificador_soporte){ if ($this->num_soportes_alquilados==0){ echo "
Este cliente no tiene alquilado ningún elemento"; return false; } //recorro el array a ver si encuentro el soporte con identificador recibido for ($i=0;$imax_alquiler_concurrente;$i++){ if (!is_null($this->soportes_alquilados[$i])){ if ($this->soportes_alquilados[$i]->dame_numero_identificacion() == $identificador_soporte){
Manual de PHP 5 - Manual completo
Página 21 de 36
echo "
Soporte devuelto: " . $identificador_soporte; echo " " . $this->soportes_alquilados[$i]->titulo . ""; $this->soportes_alquilados[$i]=null; $this->num_soportes_alquilados--; return true; } } } //si estoy aqui es que el cliente no tiene ese soporte alquilado echo "
No se ha podido encontrar el soporte en los alquileres de este cliente"; return false; }
El método devuelve recibe el identificador del soporte que debe devolver el cliente. Devuelve true si se consiguió devolver el soporte, false en caso contrario. Lo primero que hace es comprobar si el cliente tiene alquilado algún soporte, comprobando que la variable num_soportes_alquilados no sea cero. Luego hace un recorrido por el array de soportes alquilados para ver si encuentra el soporte que se desea devolver. Para cada soporte alquilado (cada casilla del array que no contenga el valor null) comprueba si el identificador es el mismo que el recibido por parámetro. Cuando encuentra el soporte, muestra un mensaje por pantalla y lo devuelve simplemente poniendo a null la casilla correspondiente del array soportes_alquilados y decrementando en uno el atributo num_soportes_alquilados. Si se encuentra el soporte, se sale de la función devolviendo true. Por lo que, si no se ha salido de la función después de hacer el recorrido por el array, sabemos que no se ha encontrado ese soporte. Entonces mostramos un mensaje en pantalla y devolvemos false. Método lista_alquileres() function lista_alquileres(){ if ($this->num_soportes_alquilados==0){ echo "
Este cliente no tiene alquilado ningún elemento"; }else{ echo "
El cliente tiene " . $this->num_soportes_alquilados . " soportes alquilados"; //recorro el array para listar los elementos que tiene alquilados for ($i=0;$imax_alquiler_concurrente;$i++){ if (!is_null($this->soportes_alquilados[$i])){ echo "
"; $this->soportes_alquilados[$i]->imprime_caracteristicas(); } } } }
Este método hace un recorrido por el array de soportes alquilados y muestra las características de cada soporte. Comprueba que el cliente tiene algo alquilado antes de hacer el recorrido. Recordar siempre, antes de llamar a un método del soporte almacenado en cada casilla del array, comprobar que el contenido de esa casilla no es null. Método imprime_caracteristicas() function imprime_caracteristicas(){ echo "
Cliente " . $this->numero . ": " . $this->nombre; echo "
Alquileres actuales: " . $this->num_soportes_alquilados }
Simplemente muestra algunos de los datos del cliente. Es un método para obtener algún dato por pantalla de un cliente. Comprobar el funcionamiento de la clase cliente Es importante señalar que, para que la clase cliente funcione, debe disponer de los códigos de
Manual de PHP 5 - Manual completo
Página 22 de 36
las distintas clases de las que hace uso (la clase soporte, cinta_video, juego y dvd). Estos códigos se pueden haber escrito en el mismo archivo o bien incluirse con unas instrucciones como estas: include include include include
"soporte.php"; "dvd.php"; "juego.php"; "cinta_video.php";
La clase cliente se puede poner en funcionamiento, para probar su correcta implementación, con un código como este: //instanciamos un par de objetos cliente $cliente1 = new cliente("Pepe", 1); $cliente2 = new cliente("Roberto", 564); //mostramos el numero de cada cliente creado echo "El identificador del cliente 1 es: " . $cliente1->dame_numero(); echo "
El identificador del cliente 2 es: " . $cliente2->dame_numero(); //instancio algunos soportes $soporte1 = new cinta_video("Los Otros", 1, 3.5, "115 minutos"); $soporte2 = new juego("Final Fantasy", 2, 2.5, "Playstation",1,1); $soporte3 = new dvd("Los Intocables", 3, 3, "Inglés y español","16:9"); $soporte4 = new dvd("El Imperio Contraataca", 4, 3, "Inglés y español","16:9"); //alquilo algunos soportes $cliente1->alquila($soporte1); $cliente1->alquila($soporte2); $cliente1->alquila($soporte3); //voy a intentar alquilar de nuevo un soporte que ya tiene alquilado $cliente1->alquila($soporte1); //el cliente tiene 3 soportes en alquiler como máximo //este soporte no lo va a poder alquilar $cliente1->alquila($soporte4); //este soporte no lo tiene alquilado $cliente1->devuelve(4); //devuelvo un soporte que sí que tiene alquilado $cliente1->devuelve(2); //alquilo otro soporte $cliente1->alquila($soporte4); //listo los elementos alquilados $cliente1->lista_alquileres();
La ejecución de este código, si todo funciona correctamente, debería devolvernos como resultado esta salida: El identificador del cliente 1 es: 1 El identificador del cliente 2 es: 564 Alquilado soporte a: Pepe Película en VHS: Los Otros 3.5 (IVA no incluido) Duración: 115 minutos Alquilado soporte a: Pepe Juego para: Playstation Final Fantasy 2.5 (IVA no incluido) Para un jugador Alquilado soporte a: Pepe
Manual de PHP 5 - Manual completo
Página 23 de 36
Película en DVD: Los Intocables 3 (IVA no incluido) Inglés y español El cliente ya tiene alquilado el soporte Los Otros Este cliente tiene 3 elementos alquilados. No puede alquilar más en este videoclub hasta que no devuelva algo No se ha podido encontrar el soporte en los alquileres de este cliente Soporte devuelto: 2 Final Fantasy Alquilado soporte a: Pepe Película en DVD: El Imperio Contraataca 3 (IVA no incluido) Inglés y español El cliente tiene 3 soportes alquilados Película en VHS: Los Otros 3.5 (IVA no incluido) Duración: 115 minutos Película en DVD: El Imperio Contraataca 3 (IVA no incluido) Inglés y español Película en DVD: Los Intocables 3 (IVA no incluido) Inglés y español
Repasando la creación de clases Para continuar la creación del videoclub y las explicaciones sobre la programación orientada a objetos (POO), vamos a programar la clase principal, que engloba a todas las clases que hemos ido creando hasta el momento. La clase principal se llama videoclub y modela el comportamiento general del videoclub. Llegado este punto sería bueno que remarcar dos cosas sobre el desarrollo de programas orientados a objetos. 1. La clase principal de un sistema que deseamos modelar en POO se suele llamar como el propio sistema que estamos modelando. Por ejemplo, si estuviéramos creando una biblioteca, la clase principal se llamaría biblioteca. En este caso, que estamos haciendo un videoclub, la clase principal se llamará videoclub. 2. El proceso de creación de un programa POO se realiza al revés de como hemos hecho en este manual, empezando el desarrollo de la clase general y finalizando por las clases más específicas. De este modo, al crear la clase general, podemos ir viendo qué otros objetos necesitaremos, cuáles serán sus métodos y propiedades. En este manual lo hemos hecho al revés porque nos venía bien para ir describiendo las características de la POO. La clase videoclub tendrá como propiedades a los soportes en alquiler (películas o juegos) y por otra parte, los socios o clientes que alquilan los productos. Los métodos de la clase videoclub
Manual de PHP 5 - Manual completo
Página 24 de 36
serán la inclusión y listado de soportes en alquiler y de socios, el alquiler de soportes por parte de clientes. Nota:Ni que decir tiene que el videoclub que estamos creando está simplificado al máximo. Está claro que si estuviésemos creando un videoclub con el propósito de utilizarlo en producción, habría que pensar y desarrollar muchas otras funcionalidades.
Vamos ya con el código y sus explicaciones. Atributos de la clase videoclub public $nombre; private $productos; private $num_productos; private $socios; private $num_socios;
El atributo $productos será un array con los distintos soportes en alquiler. $num_productos lo utilizaremos para llevar la cuenta del número de productos que tenemos disponibles. De modo similar, $socios será un array de clientes y $num_socios llevará la cuenta de los socios que tenemos dados de alta. Aparte, nuestro videoclub tendrá un nombre, que almacenaremos en la variable $nombre. Constructor function __construct($nombre){ $this->nombre=$nombre; $this->productos=array(); $this->num_productos=0; $this->socios=array(); $this->num_socios=0; }
Este método inicializará los atributos del objeto que se está construyendo. Recibe únicamente el nombre del videoclub. Como tareas destacables están las inicializaciones de los arrays de productos y socios y la puesta a cero de los contadores que vamos a utilizar. Método incluir_producto() private function incluir_producto($nuevo_producto){ $this->productos[$this->num_productos]=$nuevo_producto; echo "
Incluido soporte " . $this->num_productos; $this->num_productos++; }
Este método ha sido declarado como private, porque sólo queremos que se llame desde dentro de la clase. Recibe el nuevo producto que se quiere dar de alta y lo guardar en el array de productos, en la posición marcada por el atributo num_productos. Luego muestra un mensaje por pantalla y por último incrementa a uno el atributo num_productos. Métodos incluir_dvd(),incluir_cinta_video() e incluir_juego() Los tres siguientes métodos que vamos a ver, instancian los tres productos con los que trabaja el videoclub y luego los introducen en array de productos llamando a incluir_producto(). function incluir_dvd($tit,$precio,$idiomas,$pantalla){ $dvd_nuevo = new dvd($tit, $this->num_productos, $precio, $idiomas, $pantalla); $this->incluir_producto($dvd_nuevo); } function incluir_cinta_video($tit,$precio,$duracion){ $cinta_video_nueva = new cinta_video($tit, $this->num_productos, $precio, $duracion); $this->incluir_producto($cinta_video_nueva); }
Manual de PHP 5 - Manual completo
Página 25 de 36
function incluir_juego($tit,$precio,$consola,$min_j,$max_j){ $juego_nuevo = new juego($tit, $this->num_productos, $precio, $consola, $min_j, $max_j); $this->incluir_producto($juego_nuevo); }
Podemos fijarnos que el número de identificación del soporte, que recibe el constructor de las cintas de vídeo, DVDs o juegos, lo generamos por medio del atributo de la clase de videclub num_productos, que guarda el número de productos dados de alta. Método incluir_socio() Este método hace las tareas de instanciación del socio nuevo y su inclusión en el array de socios. function incluir_socio($nombre,$max_alquiler_concurrente=3){ $socio_nuevo = new cliente($nombre,$this->num_socios,$max_alquiler_concurrente); $this->socios[$this->num_socios]=$socio_nuevo; echo "
Incluido socio " . $this->num_socios; $this->num_socios++; }
Reciben los datos del nuevo socio: nombre y el máximo número de películas que puede alquilar (siendo 3 el valor por defecto). Una vez instanciado el nuevo socio, lo introduce en el array, en la posición marcada por el atributo num_socios. Luego muestran un mensaje por pantalla y por último incrementan a uno los atributos num_productos o num_socios. El número de socio, que recibe entre otros parámetros, el constructor de la clase socio lo generamos por medio del contador de socios num_socios, de la clase videclub. Métodos listar_productos() y listar_socios() Dos métodos muy similares, que veremos de una sola vez. function listar_productos(){ echo "
Listado de los " . $this->num_productos . " productos disponibles:"; for ($i=0;$inum_productos;$i++){ echo "
"; $this->productos[$i]->imprime_caracteristicas(); } } function listar_socios(){ echo "
Listado de $this->num_socios socios del videoclub:"; for ($i=0;$inum_socios;$i++){ echo "
"; $this->socios[$i]->imprime_caracteristicas(); } }
Estos métodos imprimen un listado completo de los socios y productos dados de alta. Simplemente hacen un recorrido del array de productos o de socios y van imprimiendo sus características. Método alquila_a_socio() Realiza las acciones necesarias para alquiler un producto a un socio. function alquila_a_socio($numero_socio,$numero_producto){ if (is_null($this->socios[$numero_socio])){ echo "
No existe ese socio"; }elseif(is_null($this->productos[$numero_producto])){ echo "
No existe ese soporte"; }else{ $this->socios[$numero_socio]->alquila($this->productos[$numero_producto]); } }
Manual de PHP 5 - Manual completo
Página 26 de 36
Este método recibe el identificador del socio y del producto en alquiler. Antes de proceder, realiza un par de comprobaciones. La primera para ver si existe un socio con el número de socio indicado por parámetro y la segunda para ver si también existe un producto con el número de producto dado. Si todo fue bien, llama al método alquila() del socio, enviándole el producto que desea alquilar. Nota:El método alquila() del socio tiene cierta complejidad, pero ya la vimos cuando explicamos la clase socio. En este momento, por el principio de encapsulación de la POO, debemos abstraernos de su dificultad y no prestarle atención porque sabemos que funciona y no nos debe preocupar cómo lo hace.
Para probar la clase videoclub podríamos utilizar un código como este: $vc = new videoclub("La Eliana Video"); //voy a incluir unos cuantos soportes de prueba $vc->incluir_juego("Final Fantasy", 2.5, "Playstation",1,1); $vc->incluir_juego("GP Motoracer", 3, "Playstation II",1,2); $vc->incluir_dvd("Los Otros", 4.5, "Inglés y español","16:9"); $vc->incluir_dvd("Ciudad de Diós", 3, "Portugués, inglés y español","16:9"); $vc->incluir_dvd("Los Picapiedra", 3, "Español","16:9"); $vc->incluir_cinta_video("Los Otros", 4.5, "115 minutos"); $vc->incluir_cinta_video("El nombre de la Rosa", 1.5, "140 minutos"); //listo los productos $vc->listar_productos(); //voy a crear algunos socios $vc->incluir_socio("José Fuentes"); $vc->incluir_socio("Pedro García",2); $vc->alquila_a_socio(1,2); $vc->alquila_a_socio(1,3); //alquilo otra vez el soporte 2 al socio 1. // no debe dejarme porque ya lo tiene alquilado $vc->alquila_a_socio(1,2); //alquilo el soporte 6 al socio 1. //no se puede porque el socio 1 tiene 2 alquileres como máximo $vc->alquila_a_socio(1,6); //listo los socios $vc->listar_socios();
Se hace una carga de datos y una llamada a todos los métodos que hemos visto para el videoclub. Este código dará como resultado una salida como la siguiente: Incluido soporte 0 Incluido soporte 1 Incluido soporte 2 Incluido soporte 3 Incluido soporte 4 Incluido soporte 5 Incluido soporte 6 Listado de los 7 productos disponibles: Juego para: Playstation Final Fantasy 2.5 (IVA no incluido) Para un jugador
Manual de PHP 5 - Manual completo
Página 27 de 36
Juego para: Playstation II GP Motoracer 3 (IVA no incluido) De 1 a 2 Jugadores. Película en DVD: Los Otros 4.5 (IVA no incluido) Inglés y español Película en DVD: Ciudad de Diós 3 (IVA no incluido) Portugués, inglés y español Película en DVD: Los Picapiedra 3 (IVA no incluido) Español Película en VHS: Los Otros 4.5 (IVA no incluido) Duración: 115 minutos Película en VHS: El nombre de la Rosa 1.5 (IVA no incluido) Duración: 140 minutos Incluido socio 0 Incluido socio 1 Alquilado soporte a: Pedro García Película en DVD: Los Otros 4.5 (IVA no incluido) Inglés y español Alquilado soporte a: Pedro García Película en DVD: Ciudad de Diós 3 (IVA no incluido) Portugués, inglés y español El cliente ya tiene alquilado el soporte Los Otros Este cliente tiene 2 elementos alquilados. No puede alquilar más en este videoclub hasta que no devuelva algo Listado de 2 socios del videoclub: Cliente 0: José Fuentes Alquileres actuales: 0 Cliente 1: Pedro García Alquileres actuales: 2
Manual de PHP 5 - Manual completo
Página 28 de 36
Hasta aquí ha llegado por ahora el desarrollo de este videoclub, que no es muy funcional pero esperamos que haya servido para empezar a conocer las características de la programación orientada a objetos. En adelante, seguiremos este manual comentando otras particularidades de la POO en PHP 5, que también hay que conocer.
Métodos y clases abstractos en PHP 5 Una clase abstracta es la que tiene métodos abstractos. Los métodos abstractos son los que están declarados en una clase, pero no se ha definido en la clase el código de esos métodos. Esa puede ser una buena definición de clases y métodos abstractos, pero veamos con calma una explicación un poco más detallada y comprensible por todos. En ocasiones, en un sistema de herencia como el de la programación orientada a objetos (POO), tenemos entidades que declarar aunque no se puede dar su definición todavía, simplemente las deseamos definir por encima para empezar una jerarquía de clases. Pensemos en los productos lácteos (los derivados de la leche). No cabe duda que los productos lácteos son una gran familia. Incluyen a los yogures, mantequillas, quesos, helados e incluso a la propia leche. Sin embargo, los productos lácteos en si no se encuentran en la vida real. En el supermercado no te venden un producto lácteo en general. Por ejemplo, nadie compra un kilo de producto lácteo... más bien preguntarán por un litro de leche, un litro de helado o un pack de yogures. Todos los productos lácteos tienen algunas características comunes, como el porcentaje en leche o la fecha de caducidad. También tienen algunas funcionalidades comunes como conservarse o consumirse. Sin embargo, la manera de conservarse es distinta dependiendo del producto lácteo. La leche se conserva fuera de la nevera, mientras que no esté abierto el brick, y los yogures deben conservarse en la nevera en todo momento. Los quesos se conservan en la nevera, pero metidos dentro de un recipiente por si acaso desprenden olores fuertes. Por lo que respecta a los helados, se deben conservar en el congelador, siempre que deseemos que no se conviertan en líquido. Al consumir un producto lácteo la cosa también cambia, puesto que el queso se suele acompañar con pan o tostadas, la leche se bebe y el helado se toma con cuchara. En definitiva, a donde queremos demostrar es que podemos tener un conjunto de objetos que tienen unas características comunes y funcionalidades, también comunes, pero que difieren en la manera de llevarlas a cabo. Para esto está la abstracción. La clase de los productos lácteos, tendrá una serie de propiedades y unos métodos abstractos. Los métodos abstractos, como habíamos adelantado, son aquellos que no incluyen una codificación, sino que simplemente se declaran, dejando para las clases que hereden la tarea de codificarlos. En este caso, la clase producto lácteo tendrá los métodos abstractos conservarse() y consumirse(), pero no se especificará el código fuente de estos métodos (por eso son abstractos). Las clases que hereden de producto lácteo serán las encargadas de definir un código para los métodos definidos como abstractos en la clase padre. Así, cada clase que herede de producto lácteo, deberá especificar el mecanismo concreto y específico por el cual se van a conservar o consumir. Las clases que incorporan métodos abstractos se deben declarar como abstractas. Es una condición forzosa. Las clases abstractas no se pueden instanciar. Es decir, no podemos crear objetos a partir de ellas. Es algo lógico. Pensemos en los productos lácteos, estos no existen más que como una idea general. Sólo podremos encontrar productos lácteos de un tipo en
Manual de PHP 5 - Manual completo
Página 29 de 36
concreto, como leche o yogur, pero no la idea de producto lácteo en general. Una clase que herede de un producto lácteo debe definir los métodos abstractos declarados en la clase abstracta. De lo contrario, la clase que hereda estaría obligada a declararse como abstracta. En nuestro ejemplo de videoclub, tratado a lo largo de los distintos capítulos del manual de PHP 5, tenemos una clase que también sería un buen ejemplo de clase abstracta. Se trata de la clase soporte. De esta clase heredaban los distintos productos del videoclub, como películas en DVD, cintas de vídeo o juegos. No hubiera sido mala idea declarar como abstracta la clase soporte, dado que no se van a utilizar, ni existen, soportes en general, sino que lo que existen son los distintos soportes concretos. La sintaxis de la abstracción Para declarar clases y métodos abstractos se utiliza la siguiente sintaxis. abstract class nombre_clase{ //propiedades public x; private y; //métodos public function __construct(){ … } public abstract function nombre_metodo(); }
Nos fijamos que se utiliza la palabra clave "abstract" para definir las clases o métodos abstractos. Además, los métodos abstractos no llevan ningún código asociado, ni siquiera las llaves para abrir y cerrar el método.
Interfaces en PHP 5 Las interfaces son un sistema bastante común, utilizado en programación orientada a objetos. Son algo así como declaraciones de funcionalidades que tienen que cubrir las clases que implementan las interfaces. En una interfaz se definen habitualmente un juego de funciones que deben codificar las clases que implementan dicha interfaz. De modo que, cuando una clase implementa una interfaz, podremos estar seguros que en su código están definidas las funciones que incluía esa interfaz. A la hora de programar un sistema, podemos contar con objetos que son muy diferentes y que por tanto no pertenecen a la misma jerarquía de herencia, pero que deben realizar algunas acciones comunes. Por ejemplo, todos los objetos con los que comercia unos grandes almacenes deben contar con la funcionalidad de venderse. Una mesa tiene poco en común con un calefactor o unas zapatillas, pero todos los productos disponibles deben implementar una función para poder venderse. Otro ejemplo. Una bombilla, un coche y un ordenador son clases muy distintas que no pertenecen al mismo sistema de herencia, pero todas pueden encenderse y apagarse. En este caso, podríamos construir una interfaz llamada "encendible", que incluiría las funcionalidades de encender y apagar. En este caso, la interfaz contendría dos funciones o métodos, uno encender () y otro apagar().
Manual de PHP 5 - Manual completo
Página 30 de 36
Cuando se define una interfaz, se declaran una serie de métodos o funciones sin especificar ningún código fuente asociado. Luego, las clases que implementen esa interfaz serán las encargadas de proporcionar un código a los métodos que contiene esa interfaz. Esto es seguro: si una clase implementa una interfaz, debería declarar todos los métodos de la interfaz. Si no tenemos código fuente para alguno de esos métodos, por lo menos debemos declararlos como abstractos y, por tanto, la clase también tendrá que declararse como abstracta, porque tiene métodos abstractos. Código para definir una interfaz Veamos el código para realizar una interfaz. En concreto veremos el código de la interfaz encendible, que tienen que implementar todas las clases cuyos objetos se puedan encender y apagar. interface encendible{ public function encender(); public function apagar(); }
Vemos que para definir una interfaz se utiliza la palabra clave interface, seguida por el nombre de la interfaz y, entre llaves, el listado de métodos que tendrá. Los métodos no se deben codificar, sino únicamente declararse. Implementación de interfaces Ahora veamos el código para implementar una interfaz en una clase. class bombilla implements encendible{ public function encender(){ echo "
Y la luz se hizo..."; } public function apagar(){ echo "
Estamos a oscuras..."; } }
Para implementar una interfaz, en la declaración de la clase, se debe utilizar la palabra implements, seguida del nombre de la interfaz que se va a implementar. Se podrían implementar varias interfaces en la misma clase, en cuyo caso se indicarían todos los nombres de las interfaces separadas por comas. En el código de la clase estamos obligados a declarar y codificar todos los métodos de la interfaz. Nota: en concreto, PHP 5 entiende que si una clase implementa una interfaz, los métodos de esa interfaz estarán siempre en la clase, aunque no se declaren. De modo que si no los declaramos explícitamente, PHP 5 lo hará por nosotros. Esos métodos de la interfaz serán abstractos, así que la clase tendrá que definirse como abstracta. Se puede encontrar más información sobre la abstracción en el artículo Métodos y clases abstractos en PHP 5 [http://www.desarrolloweb.com/articulos/2103.php].
Ahora veamos el código de la clase coche, que también implementa la interfaz encendible. Este código lo hemos complicado un poco más. class coche implements encendible{ private $gasolina; private $bateria; private $estado = "apagado"; function __construct(){ $this->gasolina = 0; $this->bateria = 10;
Manual de PHP 5 - Manual completo
Página 31 de 36
} public function encender(){ if ($this->estado == "apagado"){ if ($this->bateria > 0){ if ($this->gasolina > 0){ $this->estado = "encendido"; $this->bateria --; echo "
Enciendo... estoy encendido!"; }else{ echo "
No tengo gasolina"; } }else{ echo "
No tengo batería"; } }else{ echo "
Ya estaba encendido"; } } public function apagar(){ if ($this->estado == "encendido"){ $this->estado = "apagado"; echo "
Apago... estoy apagado!"; }else{ echo "
Ya estaba apagado"; } } public function cargar_gasolina($litros){ $this->gasolina += $litros; echo "
Cargados $litros litros"; } }
A la vista del anterior código, se puede comprobar que no hay mucho en común entre las clases bombilla y coche. El código para encender una bombilla era muy simple, pero para poner en marcha un coche tenemos que realizar otras tareas. Antes tenemos que ver si el coche estaba encendido previamente, si tiene gasolina y si tiene batería. Por su parte, el método apagar hace una única comprobación para ver si estaba o no el coche apagado previamente. También hemos incorporado un constructor que inicializa los atributos del objeto. Cuando se construye un coche, la batería está llena, pero el depósito de gasolina está vacío. Para llenar el depósito simplemente se debe utilizar el método cargar_gasolina(). Llamadas polimórficas pasando objetos que implementan una interfaz Las interfaces permiten el tratamiento de objetos sin necesidad de conocer las características internas de ese objeto y sin importar de qué tipo son... simplemente tenemos que saber que el objeto implementa una interfaz. Por ejemplo, tanto los coches como las bombillas se pueden encender y apagar. Así pues, podemos llamar al método encender() o apagar(), sin importarnos si es un coche o una bombilla lo que hay que poner en marcha o detener. En la declaración de una función podemos especificar que el parámetro definido implementa una interfaz, de modo que dentro de la función, se pueden realizar acciones teniendo en cuenta que el parámetro recibido implementa un juego de funciones determinado. Por ejemplo, podríamos definir una función que recibe algo por parámetro y lo enciende. Especificaremos que ese algo que recibe debe de implementar la interfaz encendible, así podremos llamar a sus métodos enciende() o apaga() con la seguridad de saber que existen. function enciende_algo (encendible $algo){ $algo->encender();
Manual de PHP 5 - Manual completo
Página 32 de 36
} $mibombilla = new bombilla(); $micoche = new coche(); enciende_algo($mibombilla); enciende_algo($micoche);
Si tuviéramos una clase que no implementa la interfaz encendible, la llamada a esta función provocaría un error. Por ejemplo, un CD-Rom no se puede encender ni apagar. class cd{ public $espacio; } $micd = new cd(); enciende_algo($micd); //da un error. cd no implementa la interfaz encendible
Esto nos daría un error como este: Fatal error: Argument 1 must implement interface encendible in c:\www\ejphp5\funcion_encender.php on line 6. Queda muy claro que deberíamos implementar la interfaz encendible en la clase cd para que la llamada a la función se ejecute correctamente.
Elegir entre PHP4 y PHP5. Conviene la migración? Las dudas básicamente circulan siempre el mismo camino, y ambas elecciones tienen sus ventajas y desventajas. Intentaremos en este informe orientar a los desarrolladores a decidirse por una u otra alternativa. Es importante remarcar antes de ubicarse de lleno en el análisis de las ventajas y desventajas de una u otra opción, las principales diferencias existentes entre ambas versiones, cuales son los cambios que repercuten más fuertemente en la compatibilidad de los scripts, y que es lo que nos depara el futuro en toda esta historia. Cambios profundos La llegada de PHP5 vino emparejada de una reestructuración del Core de PHP, lo que los creadores de PHP llama Zend Engine. Así como el lejano PHP3 incluye su Zend Engine [http://www.zend.com/php5/zend-engine2.php] 0.5, y PHP4 el Zend Engine 1.0, tenemos Zend Engine 2.0 en PHP5. El cambio de versión no fue trivial; incluye la reescritura casi total del modelo de objetos, entre sus cambios más sustanciales. Esto repercute directamente en los scripts de PHP4 que utilizan clases, tanto en la compatibilidad como en performance de ejecución. Posteriormente en este artículo nos referiremos nuevamente a este tema. Veamos un ejemplo que nos muestra un cambio sustancial en la implementación del modelo de objetos:
¿Cuál es el problema en este código corriendo en PHP4? En la línea 1 instanciamos un objeto de la clase Persona. Luego le decimos que se llama Daniel. El error de implementación viene con la línea 3. El argumento $p que recibe Algo, no es mas que una copia de $persona, y eso esta MAL. ¿Porque?, mínimamente por 2 razones. La primera razón es que esta estrategia es POO-No compatible. Claramente cuando hablamos del Paradigma Orientado a Objetos, estamos casi descartando que cada objeto sea referenciado por su Identificador. Sin embargo, el Zend Engine 1.0 no está preparado para dicha acción:
La variable $cadena pasada como argumento a la función ejemplo, es copiada para su uso local dentro de dicha función. Es lo que se conoce como paso de parámetros por valor. El Zend Engine 1.0 hace exactamente esto para todas las funciones, inclusive para las que están dentro de una clase, las cuales en ese caso actúan como métodos: ,
Volviendo al ejemplo inicial de la clase persona, el método Algo recibe una copia (un clon) del objeto Persona. La segunda razón viene emparejada con la primera, siendo consecuencia de esta. Cualquier modificación del objeto Persona que se produzca dentro del método Algo, solo tendrá alcance local, y no se verá reflejado cuando la función retorne.
En ese caso la modificación del nombre que hace la función Algo al objeto Persona no se ve reflejada cuando hacemos echo $persona->getNombre(). En nuestro browser veremos "Pichongol". Este es solo un ejemplo del porque de la reestructuración tan importante en el Core de PHP. Es claro que toda reestructuración barre con cuestiones de compatibilidad, para ganar en otros skills; en este caso claramente estamos ganando en performance, al liberarnos del overhead que implica la constante copia de objetos que son argumentos de métodos y funciones. En artículos posteriores trataremos en mayor detalle y profundidad los distintos aspectos que fueron modificados, haciendo una comparativa entre como se logran en PHP4 y como se logran en PHP5. Además de explicar profundamente las diferencias en el modelo de objetos nos quedan temas pendientes como Opciones de configuración (php.ini), Conexión a MySQL [http://www.mysql.com/] (mysqli), cambios en los módulos, etc. Hecha esta introducción, estamos en condiciones de definir las distintas situaciones en las que
Manual de PHP 5 - Manual completo
Página 34 de 36
se puede encontrar el desarrollador, y que aspectos juegan a su favor o en contra según la situación en la que se encuentre. ¿Cual es mi escenario? En el momento de plantearse la pregunta, el desarrollador seguramente se ubicará en alguno de los dos escenarios posibles: " Newbie (Iniciación en PHP). " Experimentado. Newbie En el planteo de esta discusión, podríamos decir que es la situación ideal, o por lo menos la más beneficiosa. Si eres una persona que quiere arrancar en PHP, no lo dudes, PHP5 es para ti. Tus aplicaciones gozaran de las nuevas capacidades en OOP, obtendrás el beneficio de una mejor performance de ejecución (esta comprobado experimentalmente que PHP5 corre un 25% más rápido que PHP4) y tu código estará muy bien acondicionado en cuanto a la compatibilidad con el nuevo hijo que asoma: PHP6. Por cierto, no todo es color de rosas. Una de los mayores beneficios a la hora de elegir PHP para trabajar en nuestro proyecto es la gran cantidad de código que podemos encontrar en Internet, y utilizarlo para nuestros trabajos. Tenemos una gran probabilidad de que ante alguna tarea que se nos plantea, podamos encontrar algún script que nos solucione la vida, obviamente adaptándolo a nuestras necesidades. Ahora bien, no todo el código que vamos a encontrar es compatible con PHP5. De hecho la gran mayoría todavía no se ha adaptado. Es cierto que con algún setting en nuestro php.ini podemos ayudar a darle mayor compatibilidad, pero como contrapartida muchas de estas settings se eliminaran en PHP6. ¿Qué queda? Hacerlo compatible modificando el código, una tarea que para un desarrollador que se inicia no siempre es sencillo. De todas formas a no alarmarse, que los grandes proyectos (PHPNuke [http://www.phpnuke.com/], PHPBB [http://www.phpbb.com/], etc.) ofrecen compatibilidad. Experimentado En este caso, el optar por quedarse con PHP4 o pasar a PHP5 depende de nuestra aplicación. Las interrogantes que el desarrollador se puede plantear podrían ser: - ¿Mi aplicación usa clases y objetos? - ¿Mi motor de Base de datos es MySQL? - ¿Utilizo un hosting externo? - ¿Mi aplicación sufre modificaciones en cuanto a los requerimientos y lógica de negocios? Pasemos a discutir ventajas y desventajas en cada uno de los interrogantes: ¿Mi aplicación usa clases y objetos? Como pudimos comprender al comienzo de este articulo, uno de los principales esfuerzos de los diseñadores del Zend Engine radicó en el mejoramiento del modelo de objetos, basándose claramente en un referente indiscutible en esta materia como lo es Sun [http://www.sun.com/]. Salvando las diferencias, se han tomado muchas cosas de Java [http://java.sun.com/], desde convenciones de nomenclaturas hasta estrategias de implementación. Seria un desperdicio no utilizar dicho esfuerzo, sobre todo si nuestra aplicación hace un uso exhaustivo de clases y objetos. ¿Mi motor de Base de datos es MySQL? A diferencia de la estrategia de PHP4 para la conectividad PHP/MySQL, en la que el Core de PHP nos provee de un set de funciones para dicha interacción, en PHP5 MySQL nos provee de un API externo. Básicamente, la razón de este cambio fue una modificación de licencia de MySQL, que obligo a PHP a hacer de MySQL una base de datos más, y no "LA" base de datos, como venia siendo en PHP3 y PHP4.
Manual de PHP 5 - Manual completo
Página 35 de 36
De todas formas, esto no repercute en nuestro código, sino en la performance de nuestra aplicación. El hecho de que una extensión no forme parte del Core de PHP y pase a ser externa nos genera un overhead, una sobrecarga de ejecución en detrimento de la performance. Como contrapartida, PHP5 nos da la posibilidad de sacarle el mayor jugo posible a las muchas mejoras incorporadas en MySQL 4.1.3 o superior, a través del API mysqli. Esto implica hacer uso de otras funciones, modificando nuestro código. Ahora bien, ¿que tan costosa es esta reescritura? Dependerá de nuestra estrategia de conexión a base de datos. ¿Utilizamos una capa de abstracción del estilo ADOdb [http://adodb.sourceforge.net/]? Si la utilizamos estaremos mucho mejor parados frente a tal reescritura. En caso contrario el tiempo invertido será sensiblemente mayor. ¿Utilizo un hosting externo? En caso de no disponer de un hosting propio, y tener que depender de un hosting externo que nos provea de PHP, seguramente el hecho de pensar en migrar a PHP5 puede ser un problema. De hecho, estadísticas de principio de 2006 nos indican que solo alrededor del 5% de los hosting que proporcionan PHP, tienen PHP5. Esto no hace mas que reflejar la lentitud con la que se esta moviendo el proceso de traspaso de PHP4 hacia PHP5. Una pregunta que surge directamente sobre este tema es ¿Por qué? Bueno, si uno tomo una distribución de Linux, es poco probable que la versión de PHP5 sea la incluida. La conformidad de los programadores con PHP4 es grande, y mucha de la documentación existente esta escrita para PHP4. De todas formas, a no dormirse con PHP4. Un tema que se trata en la segunda parte de este artículo es lo nuevo que nos trae PHP6. Veremos que PHP5 en muchos aspectos es una transición mientras que la confirmación se llama PHP6. ¿Mi aplicación sufre modificaciones en cuanto a los requerimientos y lógica de negocios? Cuando las aplicaciones tienen requerimientos de cliente bastante cambiantes, y se emplean recursos para su mantenimiento, o utilizamos una metodología de desarrollo incremental (software versionado), lo ideal es utilizar lo último que nos proporciona nuestra plataforma de programación. Generalmente lo que se busca es un cambio gradual, modular, y sostenido. Por otro lado, si nuestras aplicaciones residen en producción sin mayores modificaciones (algún proceso batch, alguna aplicación depurada, algún algoritmo estable) y estamos conformes con su funcionamiento, quizás no sea de nuestro interés migrar hacia una nueva versión. Nos queda analizar que hay de nuevo en PHP6 y que cosas deberíamos ir teniendo en cuenta si utilizamos PHP4 o PHP5.
Autores del manual: Hay que agradecer a diversas personas la dedicación prestada para la creación de este manual. Sus nombres junto con el número de artículos redactados por cada uno son los siguientes: z
Miguel Angel Alvarez Director de DesarrolloWeb.com (16 capítulos)
z
Daniel López http://pichongol.blogspot.com/ (1 capítulo)
Manual de PHP 5 - Manual completo
Página 36 de 36
Todos los derechos de reproducción y difusión [http://www.desarrolloweb.com/copyright/] reservados a Guiarte Multimedia S.L.[http://www.guiartemultimedia.com/] Volver [http://www.desarrolloweb.com/manuales/58]
© Copyright 2013 - 2025 MYDOKUMENT.COM - All rights reserved.