Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Este artículo escrito originalmente por Luis Argerich nos introducirá a la Programación
Orientada a Objetos (POO o su versión inglesa: OOP) en PHP. En él veremos la forma de
programar menos y mejor usando conceptos de POO junto con algunos trucos de PHP.
PHP:
1. <?php
2. class Algo
3. {
4. // En PHP, las clases usualmente se nombran con la primera letra
en mayúscula.
5. var $x;
6.
7. function setX($v)
8. {
9. // Los Métodos comienzan en minúscula y luego se usan
mayúsculas para
10. // separar palabras en el nombre del método.
11. // Ejemplo : obtenerRaizCuadrada();
12. $this->x = $v;
13. }
1
14.
15. function getX()
16. {
17. return $this->x;
18. }
19.}
20. ?>
Los atributos de los objetos se definen en PHP utilizando la declaración "var" dentro de la
clase, estos atributos no tienen tipo hasta que se les asigna un valor. Un atributo puee ser un
entero, un arreglo, un arreglo asociativo o incluso otro objeto. Los métodos se definen
como funciones dentro de la clase, para acceder a los atributos dentro de los métodos se
debe utilizar $this->nombre, de otra manera, se utilizaria una variable local al método.
PHP:
1. $obj->setX(5);
2. $valor=$obj->getX();
El método setx le asigna el valor 5 al atributo x en el objeto obj (no a la clase), entonces
getx devuelve ese valor: 5 en este caso.
En realidad también se puede acceder a los atributos del objeto de esta manera: $obj->x = 6;
sin embargo esta no es una buena práctica de POO. Yo recomiendo acceder a los atributos
definiendo métodos para asignarlos y devolverlos. Serás un buen programador orientado a
objetos si considerás los atributos como innacesibles y solo utilizando métodos para
acceder a ellos. Lamentablemente, PHP aún no ofrece una manera de definir un atributo
como privado asi que una mala programación es posible.
PHP:
1. <?php
2. class Otra extends Algo
3. {
4. var $y;
5. function setY($v)
6. {
7. $this->y = $v;
8. }
9.
10. function getY()
11. {
2
12. return $this->y;
13. }
14.}
15. ?>
Objetos de la clase "Otra" ahora poseen todos los atributos y métodos de la clase padre
(Algo) más sus propios métodos y atributos. Se puede hacer:
PHP:
1. $obj2=new Otra;
2. $obj2->setX(6);
3. $obj2->setY(7);
La Herencia múltiple no está soportada por PHP así que no se puede hacer que una clase
extienda dos o más clases diferentes.
Se puedden definir Constructores en las clases. Los Constructores son métodos con el
mismo nombre de la clase y que son llamados en el momento en que se instancia un objeto,
por ejemplo:
PHP:
1. <?php
2. class Algo
3. {
4. var $x;
5.
6. function Algo($y)
7. {
8. $this->x=$y;
9. }
10.
11. function setX($v)
12. {
13. $this->x=$v;
14. }
15.
16. function getX()
17. {
18. return $this->x;
19. }
20.}
21. ?>
3
Asi que ahora se puede crear al objeto asi :
$obj=new Algo(6);
function Algo($x="3",$y="5")
Entonces:
PHP:
1. <?php
2. $obj=new Algo(); // x=3 e y=5
3. $obj=new Algo(8); // x=8 e y=5
4. $obj=new Algo(8,9); // x=8 e y=9
5. ?>
Los argumentos por defecto son utilizandos de la misma manera que en C++, asi que no es
posible pasarle un valor a Y dejando que X tome el valor por defecto, los argumentos son
asignados de izquierda a derecha y cuando no se encuentran más argumentos, y si la
función esperaba más de los que se enviaron, entonces los restantes toman sus valores por
defecto.
PHP:
1. <?php
2. function Otra()
3. {
4. $this->y=5;
5. $this->Algo(); //llamada explicita al contructor de la
clase padre.
6. }
7. ?>
4
las nuevas clases tendrán ciertas funcionalidades deseadas. No existe una manera estandar
de hacer esto en PHP, pero:
Es muy útil a veces en POO sobrecargar los Constructores para poder instanciar el objeto
de diferentes maneras (pasándole diferentes números de parámetros). Un truco para hacer
esto en PHP es:
PHP:
1. <?php
2. class MiClase
3. {
4. function MiClase()
5. {
6. $nombre="MiClase".func_num_args();
7. $this->$nombre();
8. // Notar que $this->nombre(); generalmente estaría
mal
9. // pero aqui $nombre es un string con el nombre del
10. // método que se va a llamar
11. }
12.
13. function MiClase1($x)
14. {
15. //código;
16. }
17. function MiClase2($x,$y)
18. {
19. //código;
20. }
5
21.}
22. ?>
Con este "trabajo extra" en la clase, el uso de la misma se vuelve transparente al usuario
( de la clase, no del sitio ) :
PHP:
1. <?php
2. $obj1=new MiClase('1'); // llamará a MiClase1
3. $obj2=new MiClase('1','2'); // llamará a MiClase2
4. ?>
Polimorfismo
PHP:
1. <?php
2. function dibujar($x)
3. {
4. // Supongamos que este es un método de una clase "Pizarra"
5. $x->dibujar();
6. }
7.
8. $obj=new Círculo(3,187);
9. $obj2=new Rectángulo(4,5);
10.
11.$pizarra->dibujar($obj); // llamará al método dibujar de Círculo.
12.$pizarra->dibujar($obj2); // llamará al método dibujar de
Rectángulo.
13. ?>
Luego de aprender los conceptos básicos de la POO, les puedo mostrar algunas técnicas
más avanzadas:
6
Serialización
PHP no soporta Objetos Persistentes. En POO los Objetos Persistentes son aquellos que
mantienen su estado y funcionalidad a través de múltiples invocaciones de la aplicación,
esto es, la habilidad de "grabar" el objeto a un archivo o base de datos y luego "cargarlo"
nuevamente. Este mecanismo es conocido como Serialización. PHP tiene una función de
serialización que puede ser utilizada con objetos, y devuelve una cadena que representa a
ese objeto. Sin embargo la serialización guarda los atributos pero no los métodos.
En PHP4, si uno serializa un objeto hacia una cadena $s, luego se destruye el objeto y luego
se vuelve a des-serializar el objeto hacia $obj, aún se puede tener acceso a los métodos! Yo
en realidad no recomiendo esto porque (a) La documentación no garantiza este
funcionamiento y en futuras versiones de PHP puede dejar de existir. (b) Esto puede llevar
a crear "ilusiones" de grabar el objeto serializado en una cadena y salir del script. En futuras
ejecuciones del script, no podrás des-serializar la cadena hacia un objeto y esperar que los
métodos estén alli, porque la cadena que representa al objeto no guarda los métodos del
mismo. Resumiendo, la serialización en PHP es MUY útil para guardar los atributos de un
objeto, pero solo eso. (También se pueden serializar arreglos simples y asociativos para
guardarlos en disco).
Ejemplo
PHP:
1. <?php
2. $obj=new ClaseFoo();
3. $cadena=serialize($obj);
4. // Grabamos $cadena a disco
5.
6. //...algunas miles de instrucciones después....
7.
8. //Cargamos $cadena del disco
9. $obj2 = unserialize($cadena);
10. ?>
Obtendremos los atributos pero no los métodos (de acuerdo a la documentación). Esto nos
lleva a que sea $obj2->x la única manera de acceder a los atributos (ya que no tenemos
métodos para hacerlo!) así que no intenten hacer esto en sus casas.
Hay algunas maneras de solucionar este problema, pero se las dejo para que las invetiguen,
ya que son muy "chanchas" para este lindo artículo.
7
Utilizando Clases para trabajar con datos almacenados
Una de las mejores cosas de la POO y PHP es que se pueden definir sencillamente clases
para manipular ciertas cosas y luego llamar a las clases apropiadas cuando sea necesiario.
Supongamos que tenemos un formulario HTML dónde el usuario elige un producto,
enviando su ID de producto, nosotros tenemos esa información en una base de datos y
queremos mostrar por pantalla su precio, etc, etc. Tenemos productos de diferentes tipos, y
la misma acción puede tener diferentes significados para diferentes tipos de productos. Por
ejemplo, "mostrar" un sonido puede significar reproducirlo, mientras que para otro tipo de
producto puede significar mostrar una imagen guardada en la base de datos. Entonces
podemos utilizar POO y PHP para programar menos y mejor:
Definimos una clase Producto, y los métodos que va a tener (por ejemplo "mostrar"), luego
definir las clases para distintos tipos de prouctos que extenderán a la clase Producto (clase
ProdSonido, clase ProdVisible, etc...) sobreescribiendo los métodos que definimos en
Producto en cada una de estas nuevas clases para que hagan lo que necesitamos.
Deberíamos nombrar las clases de acuerdo con la columna "tipo" que guardamos en la base
de datos para cada producto (una tabla típica de productos deberia tener id, tipo, precio,
descripción, etc). Luego, podemos recuperar el tipo de producto desde la base de datos e
instanciar un objeto de esa clase haciendo :
PHP:
1. <?php
2.
3. $obj=new $tipo();
4. $obj->accion();
5.
6. ?>
Esta es una característica muy útil de PHP, podremos luego llamar al método "mostrar" de
$obj o cualquier otro método sin importar el tipo de objeto que tengamos. Con este tipo de
técnica, no es necesario tocar el script que procesa todo, cuando se agregue un nuevo tipo
de producto, tan solo agregamos la clase que lo maneje. Esta es una técnica muy poderosa,
solo definimos los métodos que los objetos deban tener, sin importar el tipo que sea, los
implementamos de diferentes maneras en diferentes clases y los usamos para cualquier tipo
de objeto en el script principal. Sin ifs, sin 2 programadores en el mismo archivo, felicidad
eterna. ¿No están de acuerdo que programar de esta manera es simple, el mantenimiento es
más barato y la reusabilidad se vuelve un hecho ?
Si les toca dirigir un grupo de programadores se vuelve muy sencillo dividir las tareas, cada
uno sería responsable por un tipo de objeto y la clase que lo maneja. La
internacionalización (mismo sitio, diferentes idiomas) puede lograrse utilizando esta técnica,
aplicando la clase que sea neceasaria de acuerdo al campo "idioma" que el usuario elija.
8
Copiando y Clonando
Cuando creamos un objeto $obj, se puede copiar el mismo haciendo $obj2 = $obj, el nuevo
objeto es ahora una copia ( no una referencia ) de $obj así que tiene el mismo estado que
tenía $obj en el momento en que la asignación se realizó. Algunas veces no queremos esto,
simplemente queremos crear un nuevo objeto de la misma clase que $obj, llamado al
constructor del nuevo objeto como si hubiésemos utilizado la sentencia new. Esto puede
lograrse en PHP utilizando serialización y una clase base de la que las demás extienden.
Cuando serializamos un objeto, obtenemos una cadena con cierto formato, puedes
investigarlo si eres curioso, una de las cosas que esta cadena contiene es el nombre de la
clase (interesante!) y podemos extraerlo haciendo :
PHP:
1. <?php
2.
3. $cadena = serialize($obj);
4. $vec = explode(':',$cadena);
5. $nombre = str_replace("\"",'',$vec[2]);
6.
7. ?>
Asi que supongamos que creamos una clase Universo y forzamos que todas las demás
clases extiendan a Universo, podemos definir un método clonar en Universo así:
PHP:
1. <?php
2. class Universo
3. {
4. function clonar()
5. {
6. $cadena=serialize($this);
7. $vec=explode(':',$cadena);
8. $nombre=str_replace("\"",'',$vec[2]);
9. $ret = new $nombre;
10. return $ret;
11. }
12.}
13.
14.// Entonces:
15.$obj=new Algo();
16.//Algo extiende a Universo !!
17.$otro = $obj->clonar();
18.?>
9
lo que logramos de esta manera es un nuevo objeto de clase Algo creado de la misma
manera que utilizando new, el contructor es llamado, etc. No estoy muy seguro que esto sea
útil para todos, pero la Clase Universo que conoce el nombre de la clase derivada es un
interesante concepto para experimentar. El único límite es la imaginación.
Nota: Para todos los ejemplo, utilicé PHP4. Algunas de los conceptos explicados en este
artículo pueden no funcionar en PHP3.
Referencia
http://www.zonaphp.com/programacion-orientada-a-objetos-en-php/
10