Sei sulla pagina 1di 35

Introduccin a POO en PHP

La Programacin Orientada a Objetos (POO) es un paradigma de desarrollo de software que permite definir a las
entidades como clases, permitiendo agrupar tareas similares. Generalmente intimida a los programadores PHP ya
que introduce una nueva sintaxis y aparenta ser ms complicado que el cdigo estructurado. Sin embargo, hace
que nuestro cdigo sea ms fcil de leer y mantener.
Diferencias entre objetos y clases
Es importante definir las diferencias entre estos dos trminos y entender que no son sinnimos.
Una clase es como una plantilla (o molde). Define las propiedades, acciones y relaciones que posee una
entidad.
Un objeto es lo que se obtiene de la clase, es una instancia de ella.
Se pueden crear muchos objetos de una misma clase, todos ellos independientes de otros.
Estructura
La sintaxis para crear una clase es bastante simple: se utiliza la palabra class, se le indica un nombre y se
encierra su cdigo entre llaves.
Luego de crear una clase, podemos instanciar una variable de la misma, esta variable es un objeto. Para hacerlo,
usamos la palabra reservada new.
Propiedades
Una clase puede contener variables dentro, las cuales reciben el nombre de propiedades. Estas funcionan igual
que las variables normales, con la excepcin que estn atadas a la clase y slo pueden ser accesibles a travs de
un objeto de ella. Para agregar una propiedad a nuestra clase tenemos que hacer lo siguiente:
La palabra public determina la visibilidad de la propiedad, significa bsicamente que se puede acceder al miembro
<?php
class Auto
{
// cdigo
}
?>
$miAuto = new Auto;
class Auto
{
public $ruedas = 4;
}
www.nebaris.com 2
por fuera de la clase. La propiedad se crea como una variable normal y puede asignrsele un valor inicial (aunque
esto no es necesario).
Para leer la propiedad y mostrar su valor en el navegador, tenemos que acceder a ella a travs de nuestro objeto,
de la siguiente forma:
El operador flecha -> nos permite acceder a un miembro del objeto que se encuentra a su izquierda.
Mtodos
Si creamos una funcin dentro de una clase, sta recibe el nombre de mtodo. La idea es que las acciones que un
objeto puede realizar, sean definidas en la clase como mtodos.
Si volvemos a ver nuestra clase Auto, nos damos cuenta que podemos hacer algo como lo siguiente:
Como la propiedad $ruedas es pblica, podemos obtener su valor y tambin establecerlo. Esto es un error, ya que
no deberamos poder modificar la cantidad de ruedas que tiene un auto. Para solucionar este problema, tenemos
que hacer dos cosas:
1) No permitir acceder a la propiedad desde fuera de la clase, utilizando el modificador de visibilidad private:
Si queremos ejecutar el ejemplo de nuevo, obtendremos un error como el siguiente:
Las variables privadas no pueden ser accedidas por fuera de la clase.
2) Agregar un mtodo que nos permita saber cuntas ruedas tiene un auto
Creamos una funcin que llama a la propiedad a travs de la variable $this. La variable $this permite al objeto
referenciarse a si mismo.
Para poder mostrar por pantalla la cantidad de ruedas, escribimos el siguiente cdigo:
echo $miAuto->ruedas;
$miAuto->ruedas = 3;
class Auto
{
private $ruedas = 4;
}
Fatal error: Cannot access private property Auto::$ruedas in C:\...\auto.php on line xx
class Auto
{
private $ruedas = 4;
public function getRuedas()
{
return $this->ruedas;
}
}
www.nebaris.com 3
Es una convencin definir los mtodos que retornan el valor de una propiedad (getter) con el prefijo "get" y a los
que establecen el valor de una propiedad (setter) con el prefijo "set".
Supongamos que queremos establecer el nombre del propietario de un auto. Para eso vamos a crear una nueva
propiedad llamada $propietario y dos mtodos: un get y un set.
Es interesante observar que en este ejemplo la nueva propiedad no se inicializa, ya que no hace falta.
Surge una pregunta: si creo un mtodo getter y un setter para una propiedad, qu diferencia tiene esto con
establecer la propiedad como pblica?. La diferencia est en la seguridad. Si nosotros tenemos una propiedad
pblica no podemos protegerla de datos que estn mal, en cambio si creamos un mtodo setter, podemos evitar
que un usuario la establezca con un dato que no es vlido. Ej:
De esta forma, si alguien intenta hacer $miAuto->setPropietario(50), la propiedad $propietario permanecer
invariable.
Ahora probemos un ejemplo con varios objetos, para verificar que cada uno posee un propietario diferente y por
ende, que no comparten las propiedades (aunque todos pertenecen a la misma clase).
$miAuto = new Auto;
echo $miAuto->getRuedas();
class Auto
{
private $ruedas = 4;
private $propietario;
public function getRuedas()
{
return $this->ruedas;
}
public function getPropietario()
{
return $this->propietario;
}
public function setPropietario($nombre)
{
$this->propietario = $nombre;
}
}
$miAuto = new Auto;
echo "Cantidad de ruedas: " . $miAuto->getRuedas() . "<br />";
echo $miAuto->setPropietario("Gabriel");
echo "Propietario: " . $miAuto->getPropietario();
public function setPropietario($nombre)
{
if (is_string($nombre)) {
$this->propietario = $nombre;
}
}
www.nebaris.com 4
Obtendramos lo siguiente:
Constructores y Destructores
Cuando se instancia un objeto, generalmente es deseable dejar todas las propiedades del mismo en un estado
consistente. Para manejar esto, PHP ofrece un mtodo llamado __construct() (doble guin bajo), que se llama
automticamente cuando se crea un nuevo objeto. Este mtodo forma parte de los denominados "mtodos
mgicos" que PHP posee para hacer ms simple el uso de los objetos.
<?php
class Auto
{
private $ruedas = 4;
private $propietario;
public function getRuedas()
{
return $this->ruedas;
}
public function getPropietario()
{
return $this->propietario;
}
public function setPropietario($nombre)
{
if (is_string($nombre)) {
$this->propietario = $nombre;
}
}
}
$miAuto = new Auto;
$otroAuto = new Auto;
$tercerAuto = new Auto;
echo $miAuto->setPropietario("Gabriel");
echo "Propietario: " . $miAuto->getPropietario() . "<br />";
echo $otroAuto->setPropietario("Pedro");
echo "Propietario: " . $otroAuto->getPropietario() . "<br />";
echo $tercerAuto->setPropietario("Antonio");
echo "Propietario: " . $tercerAuto->getPropietario() . "<br />";
?>
Propietario: Gabriel
Propietario: Pedro
Propietario: Antonio
www.nebaris.com 5
Para continuar con el ejemplo anterior, supongamos que queremos establecer la propiedad $propietario en "Sin
dueo" al momento de crear un objeto.
De esta forma, podemos acceder a la propiedad sin indicar un propietario para ella, estamos seguros que va a
poseer un valor que tenga sentido. Tambin indicamos cul es el valor para la propiedad $ruedas; ya que toda
inicializacin de variables debera hacerse en el constructor.
De la misma forma que existen los constructores, existen los destructores, denominados __destruct(). Estos
mtodos se utilizan para limpiar el objeto y liberar todos los recursos que pudieron ser abiertos por el mismo
(archivos, bases de datos, etc.). Estos mtodos se ejecutan cuando finaliza la ejecucin del script. Para ver un
ejemplo, agreguemos un destructor que informe que se ejecut (para poder ver su funcionamiento).
class Auto
{
private $ruedas;
private $propietario;
public function __construct()
{
$this->propietario = "Sin dueo";
$this->ruedas = 4;
}
public function getRuedas()
{
return $this->ruedas;
}
public function getPropietario()
{
return $this->propietario;
}
public function setPropietario($nombre)
{
if (is_string($nombre)) {
$this->propietario = $nombre;
}
}
}
$miAuto = new Auto;
echo "Propietario: " . $miAuto->getPropietario() . "<br />";
class Auto
{
private $ruedas;
private $propietario;
public function __construct()
{
$this->propietario = "Sin dueo";
$this->ruedas = 4;
}
www.nebaris.com 6
Este script nos mostrar lo siguiente en el navegador:
Tambin es posible destruir un objeto de manera explcita utilizando la funcin unset().
public function getRuedas()
{
return $this->ruedas;
}
public function getPropietario()
{
return $this->propietario;
}
public function setPropietario($nombre)
{
if (is_string($nombre)) {
$this->propietario = $nombre;
}
}
public function __destruct()
{
echo 'El objeto fue destruido';
}
}
$miAuto = new Auto;
echo "Propietario: " . $miAuto->getPropietario() . "<br />";
Propietario: Sin dueo
El objeto fue destruido
unset($miAuto);
www.nebaris.com 7
Convertir a String
Veamos este ejemplo:
Que ocurrir cuando intentemos mostrar el objeto como un String? Lo que obtendremos ser lo siguiente:
Esto se debe a que no se puede hacer un parseo directo del tipo de nuestra clase al tipo String. Para solucionar
este problema, podemos hacer uso de un mtodo mgico llamado __toString().
Vamos a corregir el ejemplo anterior usando el mtodo __toString():
<?php
class Auto
{
private $marca;
private $modelo;
public function __construct()
{
$this->marca = "Renault";
$this->modelo = "Clio";
}
public function getDescripcion()
{
return $this->marca . " " . $this->modelo;
}
}
// creo un objeto de la clase Auto
$miAuto = new Auto;
// muestro el objeto como un String
echo $miAuto;
?>
<?php
class Auto
{
private $marca;
private $modelo;
public function __construct()
{
$this->marca = "Renault";
www.nebaris.com 8
Este cdigo funciona correctamente. Al intentar convertir la clase al tipo String, se llama automticamente al
mtodo __toString(), el cual nosotros le definimos que llame al mtodo getDescripcion().
Para ver una lista detallada de todos los mtodos mgicos que hay, podemos ver la pgina oficial de PHP.
Herencia
Una clase puede heredar los mtodos y propiedades de otra clase utilizando la palabra reservada extends. La
herencia se utiliza para crear clases ms especficas. Esto nos ayuda a reutilizar cdigo y modularizar nuestro
proyecto.
Veamos un ejemplo, primero crearemos una clase Persona:
$this->modelo = "Clio";
}
public function getDescripcion()
{
return $this->marca . " " . $this->modelo;
}
public function __toString()
{
return $this->getDescripcion();
}
}
// creo un objeto de la clase Auto
$miAuto = new Auto;
// muestro el objeto como un String
echo $miAuto;
?>
class Persona
{
private $nombre;
private $apellido;
public function setNombre($nombre)
{
$this->nombre = $nombre;
}
public function setApellido($apellido)
{
$this->apellido = $apellido;
}
public function getNombreCompleto()
{
return $this->nombre . " " . $this->apellido;
}
www.nebaris.com 9
Tenemos dos propiedades y sus respectivos setters. Tambin tenemos un getter que nos da el nombre completo
de la persona.
Ahora creemos una clase Empleado que herede de Persona.
Vemos que el empleado tiene un constructor que espera un nombre, un apellido y un sueldo. Con estos datos
llenar las propiedades de su clase padre y finalmente su propiedad sueldo.
Mostremos por pantalla los resultados:
Esto mostrar:
Podemos ver lo importante que se torna la herencia al momento de codificar. Tenemos dos clases que comparten
ciertas propiedades, con lo cual podemos hacer que una sea una forma ms especfica y con eso estamos
reutilizando parte del cdigo que ya habamos escrito. Hay que tener en cuenta que una clase hija obtiene todos
los miembros pblicos o protegidos de la clase padre, sin embargo, no puede acceder a los miembros privados.
Sobrescritura de mtodos heredados
Como vimos, cuando la clase Empleado hereda de Persona, obtiene todas sus propiedades y mtodos. Ahora
supongamos que queremos modificar en Empleado el mtodo getNombreCompleto() para que muestre el ttulo que
tiene la persona en la compaa. Esta accin se llama sobrescritura de mtodos y se basa en redefinir el proceso
}
class Empleado extends Persona
{
private $sueldo;
public function __construct($nombre, $apellido, $sueldo)
{
$this->setNombre($nombre);
$this->setApellido($apellido);
$this->sueldo = $sueldo;
}
public function getSueldo()
{
return "$" . $this->sueldo;
}
}
// creo un objeto de la clase Empleado
$juan = new Empleado("Robert", "Smith", "6000");
// muestro el nombre y apellido
echo "Empleado: " . $juan->getNombreCompleto() . "<br />";
// muestro el sueldo
echo "Sueldo: " . $juan->getSueldo();
Empleado: Robert Smith
Sueldo: $6000
www.nebaris.com 10
del mtodo padre.
Veamoslo en un ejemplo:
Ac hicimos un par de modificaciones: Primero agregamos una nueva propiedad llamada $titulo y modificamos el
constructor para que la reciba al crear el objeto. Despus sobrescribimos el mtodo getNombreCompleto() para
mostrar el ttulo. Lo interesante, es que podemos llamar a la funcin del padre que estamos sobrescribiendo, si
utilizamos la forma parent::.
Esto mostrar:
Evitando la herencia
La mayor parte del tiempo, permitir extender tus clases a travs de la herencia es algo bueno; es parte de lo que
hace a la programacin orientada a objetos tan poderoso.
Sin embargo, existen veces donde por distintos motivos sobrescribir un mtodo o heredar una clase entera puede
traernos problemas (de seguridad, de complejidad, de lgica, etc.).
En dichas situaciones, lo mejor es indicar que un mtodo no puede ser sobrescrito por una clase hija, utilizando la
palabra reservada final.
Por ejemplo, creamos un ABM (Alta, Baja, Modificacin) y tenemos un mtodo login(), el cual por un tema de
seguridad lo marcamos como final para que nadie pueda sobrescribirlo. Luego de un tiempo se crea un nuevo
ABM y se intenta sobrescribir el mtodo login() de la siguiente manera:
class Empleado extends Persona
{
private $sueldo;
private $titulo;
public function __construct($nombre, $apellido, $sueldo, $titulo)
{
$this->setNombre($nombre);
$this->setApellido($apellido);
$this->sueldo = $sueldo;
$this->titulo = $titulo;
}
public function getSueldo()
{
return "$" . $this->sueldo;
}
public function getNombreCompleto()
{
return $this->titulo . " " . parent::getNombreCompleto();
}
}
Empleado: Gerente Robert Smith
Sueldo: $6000
class ABM
{
www.nebaris.com 11
Si eso llega a pasar, obtendremos un bonito error como el siguiente:
Si en cambio, hubiramos querido que no se pudiera heredar de la clase ABM podamos hacer lo siguiente:
public final function login ()
{
// codigo
}
}
class NuevoABM extends ABM
{
public function login ()
{
// codigo
}
}
$obj = new NuevoABM();
final class ABM
{
...
}
www.nebaris.com 12
Asignando visibilidad
La visibilidad nos permite tener ms control sobre los mtodos y propiedades de los objetos. Nos permite indicar
cmo y desde dnde se pueden acceder los miembros.
Existen tres formas de visibilidad: pblica (public), protegida (protected) y privada (private).
Miembros pblicos
Cuando un miembro es declarado como pblico, significa que puede ser accedido desde cualquier lugar, tanto
desde dentro de la clase como de forma externa.
Miembros protegidos
Los miembros protegidos slo pueden ser accedidos desde dentro de la clase misma o a travs de las clases
descendientes (clases que heredan de la clase que posee el miembro protegido).
Veamos un ejemplo del uso de estas dos propiedades de visibilidad. Vamos a crear una clase Animal que posea
una propiedad llama patas, junto con su setter y getter. El getter ser pblico, mientras que el setter ser
protegido. Luego creamos una clase llamada Gato que hereda de Animal, instanciamos un objeto de esta clase e
intentamos llamar al getter y setter.
<?php
class Animal
{
protected $patas = 4;
protected function setPatas($cantidad)
{
$this->patas = $cantidad;
}
public function getPatas()
{
return $this->patas . "<br />";
}
}
class Gato extends Animal
{
//...
}
// creamos el objeto
$bolaDeNieve = new Gato();
// llamamos al getter
echo 'Cantidad de patas: ' . $bolaDeNieve->getPatas();
// llamamos al setter y obtenemos un error
$bolaDeNieve->setPatas(3);
www.nebaris.com 13
Este es el resultado que obtenemos:
Como Gato hereda de Animal y setPatas() tiene visibilidad protegida; podemos crear un mtodo en Gato que llame
a setPatas() y ah poder indicarle cuntas patas tiene el gato.
De esta forma no obtendremos ningn error al utilizar el cdigo.
Miembros privados
Una propiedad o mtodo declarados como privados slo se pueden acceder desde dentro de la clase que los
define. Esto significa que, incluso las clases derivadas no podrn tener acceso al miembro privado.
En nuestro ejemplo anterior, tenemos el mtodo getPatas() que es pblico (para que todos puedan acceder a l) y
el mtodo setPatas() que es protegido (para que slo se pueda acceder desde dentro de la clase y sus clases
herederas). Ahora, la propiedad patas, debera ser privada; de esta forma controlaramos el acceso a ella y
mejoraramos la seguridad de nuestro cdigo.
Modificamos el ejemplo y demostramos que no es posible acceder a una variable privada desde otro lugar que no
sea dentro de la clase misma.
?>
Cantidad de patas: 4
Fatal error: Call to protected method Animal::setPatas() from context '' in ...
class Gato extends Animal
{
public function establecerPatas($patas)
{
$this->setPatas($patas);
}
}
// creamos el objeto
$bolaDeNieve = new Gato();
// llamamos al getter
echo 'Cantidad de patas: ' . $bolaDeNieve->getPatas();
// utilizamos el mtodo que llama a setPatas
$bolaDeNieve->establecerPatas(3);
//mostramos la nueva cantidad de patas
echo 'Cantidad de patas: ' . $bolaDeNieve->getPatas();
<?php
class Animal
{
private $patas = 4;
protected function setPatas($cantidad)
www.nebaris.com 14
Gracias a la visibilidad podemos ocultar lo que no hace falta que se vea desde afuera, con lo cual obtenemos el
concepto de caja negra y ayudamos a desacoplar nuestras clases. Hay que tratar de declarar como privados la
mayor cantidad de miembros posibles, para tener mejor encapsulamiento y permitir cambiar la forma interna de las
clases sin afectar el cdigo de nuestro programa.
Miembros estticos
Un miembro declarado como esttico (static), puede ser accedido sin instanciar la clase que lo contiene
previamente. El miembro esttico existe aunque no haya ningn objeto de la clase y todos los objetos de clase
comparten el mismo miembro esttico.
Existen un par de cosas a tener en cuenta a la hora de trabajar con propiedades y mtodos estticos:
Como los mtodos estticos se pueden llamar sin una instancia del objeto creada, $this no se puede usar
dentro del mtodo
Las propiedades estticas no pueden ser accedidas utilizando el operador flecha ->
Llamar a un mtodo no esttico de manera esttica genera un warning.
Para acceder al miembro esttico desde dentro de la clase se utiliza self::
Para acceder al miembro esttico desde fuera de la clase se utiliza la forma Clase:$miembro
.
{
$this->patas = $cantidad;
}
public function getPatas()
{
return $this->patas . "<br />";
}
}
class Gato extends Animal
{
public function establecerPatas($patas)
{
$this->setPatas($patas);
}
// este mtodo va a fallar, ya que quiere acceder
// a una propiedad privada de la clase padre
public function accederAPatas()
{
return $this->patas;
}
}
// creamos el objeto
$bolaDeNieve = new Gato();
// producimos el error
echo $bolaDeNieve->accederAPatas();
?>
www.nebaris.com 15
Obtendremos este resultado:
Por qu utilizar la programacin orientada a objetos?
Cada uno puede utilizar la forma de escribir cdigo qu ms se adece a su forma de trabajo. A pesar de ello,
existen argumentos que pueden ayudar a que adoptemos paradigmas que han demostrado ser realmente muy
eficaces:
Facilidad de implementacin: Al principio la POO puede parecer complicada, pero en realidad provee una
forma ms simple de programar. Es ms fcil lidiar con los datos, ya que se puede pasar un objeto con
muchas propiedades como parmetros en lugar de una lista enorme de variables. Adems, como es posible
que varias instancias de la misma clase existan al mismo tiempo, nos ahorra trabajo al tener que usar largos
conjuntos de datos.
Mejor organizacin: Otro beneficio de la POO, es el de poder catalogar cdigo de manera simple. Cada
clase puede estar en un archivo separado, manteniendo una convencin uniforme de nombrado. Esto hace
que sea ms simple la bsqueda, la reutilizacin y permite la portabilidad en nuevas aplicaciones.
Mejor mantenimiento: Debido a la naturaleza compacta de la POO los cambios son mucho ms simples de
realizar.
<?php
class MiClase
{
public static $cantidadDeObjetos = 0;
public function __construct()
{
++self::$cantidadDeObjetos;
}
}
// al llamar a una propiedad esttica
// el signo $ va despus de los :
echo 'Cantidad de objetos: ' . MiClase::$cantidadDeObjetos . '<br />';
$obj1 = new MiClase();
echo 'Cantidad de objetos: ' . MiClase::$cantidadDeObjetos . '<br />';
$obj2 = new MiClase();
echo 'Cantidad de objetos: ' . MiClase::$cantidadDeObjetos . '<br />';
echo 'Cantidad de objetos: ' . $obj2::$cantidadDeObjetos . ', mostrando desde el objeto';
?>
Cantidad de objetos: 0
Cantidad de objetos: 1
Cantidad de objetos: 2
Cantidad de objetos: 2, mostrando desde el objeto
www.nebaris.com 16
Mtodos mgicos en PHP
Introduccin
Ya vimos algunos mtodos mgicos de PHP como: los constructores, destructores y la representacin en string.
Los mtodos mgicos se identifican con un prefijo, dos guiones bajos "__", y funcionan como interceptores que se
llaman automticamente cuando ocurre una condicin dada.
__get()
El mtodo __get() se llama cuando un cdigo intenta acceder a una propiedad que no es accesible. Acepta un
argumento, que es el nombre de la propiedad. Debe retornar un valor, el cual ser tratado como el valor de la
propiedad.
Un popular uso del mtodo __get() es extender el control de acceso, creando propiedades de "slo lectura". Por
ejemplo, en este ejercicio, tenemos una propiedad privada llamada nombre y permitimos que la misma sea leda
utilizando este mtodo mgico.
Algo interesante de este ejemplo es que adems utilizamos "variables variables". Las variables variables son
nombres de variables que se pueden definir y utilizar dinmicamente dentro de una variable. En el ejemplo,
$this->$propiedad se traduce como $this->nombre.
__set()
El mtodo mgico __set() es llamado cuando se intenta modificar el valor de una propiedad que no es accesible.
Acepta dos argumentos, que son: el nombre de la propiedad y el valor. r
<?
class Empleado {
private $nombre = "Pablo";
public function __get($propiedad) {
if(isset($this->$propiedad)) {
return $this->$propiedad;
}
return null;
}
}
$e = new Empleado();
echo $e->nombre;
?>
<?
class Empleado {
private $nombre;
www.nebaris.com 17
Siguiendo con el ejemplo anterior, vemos como podemos indicar el valor de una variable que en principio est
declarada como privada.
__isset()
Este mtodo se llama cuando el cdigo ejecuta la funcin isset() sobre una propiedad que no est accesible.
Acepta un argumento, que es el nombre de la propiedad y debe retornar un valor booleano representando la
existencia de un valor.
public function __get($propiedad) {
if(isset($this->$propiedad)) {
return $this->$propiedad;
}
return null;
}
public function __set($propiedad, $valor) {
$this->$propiedad = $valor;
}
}
$e = new Empleado();
$e->nombre = "Gabriel";
echo $e->nombre;
?>
<?
class Empleado {
private $nombre;
public function __set($nombre, $valor) {
$this->$nombre = $valor;
}
public function __isset($propiedad) {
return isset($this->$propiedad);
}
}
$e = new Empleado();
$e->nombre = "Gabriel";
if(isset($e->nombre)) {
echo "variable definida";
}
else {
echo "variable no definida";
}
?>
www.nebaris.com 18
__unset()
De la misma forma que __isset(), __unset() se llama cuando un cdigo intenta aplicar unset() sobre una
propiedad que no est accesible. Acepta un argumento, que es el nombre de la propiedad. Recordemos que
unset() destruye las variables especificadas.
_setstate()
Este mtodo se llama cuando la funcin var_export() se aplica sobre el objeto. Esta funcin se utiliza para
obtener informacin estructurada sobre una variable dada.
<?
class Empleado {
private $nombre;
public function __set($nombre, $valor) {
$this->$nombre = $valor;
}
public function __unset($propiedad) {
unset($this->$propiedad);
}
}
$e = new Empleado();
$e->nombre = "Gabriel";
unset($e->nombre);
?>
<?
class Empleado {
private $nombre;
public function __set($propiedad, $valor) {
$this->$propiedad = $valor;
}
public static function __set_state(array $arreglo) {
foreach ($arreg as $key => $value) {
echo("$key ==> $value <br>");
}
}
}
$e = new Empleado();
$e->nombre = "Gabriel";
echo var_export($e, true);
?>
www.nebaris.com 19
El resultado que obtendramos sera el siguiente:
Empleado::_setstate(array( 'nombre' => 'Gabriel', ))
Hay que estar realmente seguros que lo producido por este mtodo sea cdigo PHP vlido, ya que sino
obtendremos errores.
__clone ()
Para crear una copia de un objeto se utiliza la palabra reservada clone.
Cuando se copia un objeto, PHP lleva a cabo una copia superficial de las propiedades del mismo y las
propiedades que sean referencias a otras variables, mantendrn las referencias.
Una vez que la clonacin ha finalizado, se llamar al mtodo __clone() (si el mismo est definido), para permitir
realizar cambios necesarios sobre las propiedades de la copia.
Es importante recalcar que __clone() no es una sobrecarga, el proceso normal de clonacin ocurre y luego se
ejecuta el cdigo dentro de __clone().
$copia = clone $objeto;
<?
class Biblioteca {
static $cantidadDeLibros = 0;
public $libros;
public function __construct() {
$this->libros = ++self::$cantidadDeLibros;
}
public function __clone() {
$this->libros = ++self::$cantidadDeLibros;
}
}
$b = new Biblioteca();
// 1
echo $b->libros . "<br>";
$b2 = clone $b;
// 2
echo $b2->libros . "<br>";
?>
www.nebaris.com 20
__construct()
Cuando se instancia un objeto, generalmente es deseable dejar todas las propiedades del mismo en un estado
consistente. PHP ofrece un mtodo llamado __construct(), que se llama automticamente cuando se crea un
nuevo objeto.
Veamos un ejemplo de su uso.
__destruct()
De la misma forma que existen los constructores, existen los destructores, denominados __destruct(). Estos
mtodos se utilizan para limpiar el objeto y liberar todos los recursos que pudieron ser abiertos por el mismo
(archivos, bases de datos, etc.). Se ejecutan cuando finaliza la ejecucin del script.
class Auto
{
private $ruedas;
private $propietario;
public function __construct()
{
$this->propietario = "Sin dueo";
$this->ruedas = 4;
}
public function getRuedas()
{
return $this->ruedas;
}
public function getPropietario()
{
return $this->propietario;
}
public function setPropietario($nombre)
{
if (is_string($nombre)) {
$this->propietario = $nombre;
}
}
}
$miAuto = new Auto;
echo "Propietario: " . $miAuto->getPropietario() . "<br />";
class Auto
{
private $ruedas;
private $propietario;
www.nebaris.com 21
Este script nos mostrar lo siguiente en el navegador:
__toString()
Veamos este ejemplo:
public function __construct()
{
$this->propietario = "Sin dueo";
$this->ruedas = 4;
}
public function getRuedas()
{
return $this->ruedas;
}
public function getPropietario()
{
return $this->propietario;
}
public function setPropietario($nombre)
{
if (is_string($nombre)) {
$this->propietario = $nombre;
}
}
public function __destruct()
{
echo 'El objeto fue destruido';
}
}
$miAuto = new Auto;
echo "Propietario: " . $miAuto->getPropietario() . "<br />";
Propietario: Sin dueo
El objeto fue destruido
<?php
class Auto
{
private $marca;
private $modelo;
public function __construct()
{
$this->marca = "Renault";
$this->modelo = "Clio";
}
www.nebaris.com 22
Si intentamos mostrar el objeto como si fuera un string, obtendremos un error en tiempo de ejecucin. Esto se
debe a que no se puede hacer un parseo directo del tipo de nuestra clase al tipo String. Para solucionar este
problema, podemos hacer uso de un mtodo mgico llamado __toString().
Este cdigo funciona correctamente. Al intentar convertir la clase al tipo String, se llama automticamente al
mtodo __toString(), el cual nosotros le definimos tal que llame al mtodo getDescripcion().
public function getDescripcion()
{
return $this->marca . " " . $this->modelo;
}
}
// creo un objeto de la clase Auto
$miAuto = new Auto;
// muestro el objeto como un String
echo $miAuto;
?>
<?php
class Auto
{
private $marca;
private $modelo;
public function __construct()
{
$this->marca = "Renault";
$this->modelo = "Clio";
}
public function getDescripcion()
{
return $this->marca . " " . $this->modelo;
}
public function __toString()
{
return $this->getDescripcion();
}
}
// creo un objeto de la clase Auto
$miAuto = new Auto;
// muestro el objeto como un String
echo $miAuto;
?>
www.nebaris.com 23
Serializacin de objetos
La serializacin es un proceso mediante el cual se convierte cualquier dato en un string. Es utilizado para
almacenar objetos enteros en un archivo o base de datos. Un problema que acarrea la serializacin, es que no
todo puede ser serializado. PHP nos ofrece mtodos para manejar este problema.
__sleep()
Este mtodo se llama cuando la funcin serialize() se llama sobre el objeto. No acepta parmetros y debe
devolver un arreglo de todas las propiedades que deben ser serializadas.
__wakeup()
El mtodo __wakeup() se llama cuando se aplica la funcin unserialize() sobre el objeto. No acepta argumentos y
no necesita devolver nada en especial. Sirve para restablecer conexiones con bases de datos o alterar algn
atributo que se haya perdido con la serializacin.
<?php
class Auto
{
private $marca;
private $modelo;
public function __construct()
{
$this->marca = "Reanault";
$this->modelo = "Clio";
}
public function __sleep()
{
return array("marca", "modelo");
}
}
$miAuto = new Auto();
// imprime:
// object(Auto)#1 (2)
// { ["marca":"Auto":private]=> string(8) "Reanault"
// ["modelo":"Auto":private]=> string(4) "Clio" }
var_dump($miAuto);
$miAutoSerializado = serialize($miAuto);
//imprime:
//string(80) "O:4:"Auto":2:{s:11:"Automarca";
//s:8:"Reanault";s:12:"Automodelo";s:4:"Clio";}"
var_dump($miAutoSerializado);
?>
www.nebaris.com 24
Podemos verificar que al hacer el var_dump(), obtenemos el mismo objeto que al principio.
__call()
Este mtodo nos permite controlar el comportamiento cuando llamamos a un mtodo no accesible en el objeto.
<?php
class Auto
{
private $marca;
private $modelo;
public function __construct()
{
$this->marca = "Reanault";
$this->modelo = "Clio";
}
public function __sleep()
{
return array("marca", "modelo");
}
public function __wakeup()
{
echo 'finalizada la deserializacin';
}
}
$miAuto = new Auto();
// imprime:
// object(Auto)#1 (2)
// { ["marca":"Auto":private]=> string(8) "Reanault"
// ["modelo":"Auto":private]=> string(4) "Clio" }
var_dump($miAuto);
$miAutoSerializado = serialize($miAuto);
//imprime:
//string(80) "O:4:"Auto":2:{s:11:"Automarca";
//s:8:"Reanault";s:12:"Automodelo";s:4:"Clio";}"
var_dump($miAutoSerializado);
$miAutoDeserializado = unserialize($miAutoSerializado);
// imprime:
// object(Auto)#1 (2)
// { ["marca":"Auto":private]=> string(8) "Reanault"
// ["modelo":"Auto":private]=> string(4) "Clio" }
var_dump($miAutoDeserializado);
?>
www.nebaris.com 25
Recibe dos parmetros: el nombre del mtodo que se desea invocar y un arreglo con todos los parmetros
pasados.
<?php
class Auto
{
public function __call($metodo, $parametros){
$mensaje = "Mtodo inaccesible: Mtodo -> '" . $metodo . "', Parmetros -> '";
// mostramos los parmetros pasados
foreach($parametros as $parametro){
$mensaje .= $parametro . "' ";
}
echo $mensaje;
}
}
$miAuto = new Auto();
// imprime: Mtodo inaccesible: Mtodo -> 'miMetodo', Parmetros -> '120'
$miAuto->acelerar(120);
?>
www.nebaris.com 26
Introduccin al patrn MVC en PHP
En el artculo de hoy veremos cmo funciona el patrn MVC sin utilizar ningn framework. Desarrollaremos un hola
mundo en MVC para entender qu partes componen al patrn y cul es la idea detrs del mismo.
Introduccin
Hay muchos desarrolladores PHP a los que les es complicado pasar de trabajar sin framework a incluir un
framework en sus desarrollos. Mucho se debe a que la mayora de los frameworks profesionales de PHP funcionan
con el patrn MVC y este parece difcil de comprender en un principio.
El objetivo de este artculo no es crear un framework, sino crear unas clases bsicas para entender qu es MVC y
observar que no es algo difcil, ni aterrador. Por esta razn, en este artculo no se hablarn de motores de
template, ni estructura de directorio, DAO u ORMs; slo MVC, liso y llano.
Qu es MVC?
MVC (o Modelo Vista Controlador) es un patrn de arquitectura de software que separa los datos y la lgica de
negocio de la interfaz de usuario en una aplicacin. El patrn fue creado por Trygve Reenskaug en los setenta,
aunque no fue hasta 1988 que se expres como concepto general en un artculo.
En la primer definicin de MVC el controlador era definido como "el mdulo que se ocupa de la entrada" y la vista
era "el mdulo que se ocupa de la salida". El controlador no era el que invocaba a la vista, ni le pasaba los datos.
Hay que tener en cuenta que el patrn MVC se postul en ese entonces para las aplicaciones de escritorio (los
pedidos tienen estado); mientras que actualmente se lo utiliza sobre todo en aplicaciones web (pedidos sin estado,
debido al protocolo HTTP). Actualmente, el controlador es un intermediario de la comunicacin entre el modelo y la
vista y unifica la validacin.
En este artculo vamos a tomar la descripcin original de MVC para desarrollar nuestro ejemplo, con lo cual se
har ms simple entender los roles. Para desarrollar con el patrn MVC actual, lo ms recomendable es elegir uno
de los muchos frameworks profesionales que nos ofrece la comunidad PHP (lectura recomendada: Introduccin a
CodeIgniter).
Modelo Vista Controlador
El modelo
En su forma ms simple, el modelo almacena datos que son accedidos desde la vista y escritos por el controlador.
El modelo es la parte ms compleja del sistema y contiene toda la lgica que es especfica de la aplicacin.
Adems, incluye a las entidades de dominio. No posee conocimiento de los controladores o vistas que pueden
utilizarlo.
Un modelo, por ejemplo, puede representar a un "usuario" en el sistema y manejar todas las operaciones que
puede llevar a cabo un usuario.
El modelo no es:
un simple acceso a datos
una clase que representa una tabla en la base de datos
www.nebaris.com 27
La vista
Se encarga de mostrarle al visitante los resultados del sistema, es el encargado de generar el cdigo HTML.
Accede de forma directa al modelo y lo consulta para obtener los datos. Puede crear llamadas al controlador.
Como dijimos antes, en MVC original, las vistas obtienen los datos directamente, no necesitan que el controlador
se los provea.
La vista no:
est ausente de lgica
recibe datos del controllador
El controlador
El controlador se encarga de tomar la entrada del usuario y modificar el modelo si es requerido. Si no existe
interaccin del usuario, no es necesario utilizar el controlador.
El controlador accede al modelo, pero no posee ninguna lgica para mostrarlo, todo lo que hace es responder a
los pedidos del usuario.
El controlador no es:
un mediador entre la vista y el modelo
el lugar donde se inicializan las vistas
Flujo del sistema
El programa va a funcionar de la siguiente manera:
El modelo, la vista y el controlador se inicializan
Se muestra la vista al usuario leyendo datos del modelo
El usuario interacta con la vista, lo cual llama a una accin especfica del controlador
El controlador modifica el modelo
La vista se refresca, mostrando el cambio en el modelo
Cdigo
En este ejemplo vamos a utilizar orientacin a objetos, te recomiendo leer estos artculos antes:
Introduccin a la Programacin Orientada a Objetos
Introduccin a POO en PHP - parte 1
Empezamos creando el modelo:
Nuestro modelo posee una variable que mostrar un texto y un constructor que es el encargado de indicar el valor
inicial de dicha variable.
class Modelo {
public $texto;
public function __construct() {
$this->texto = 'Hola mundo';
}
}
www.nebaris.com 28
La vista:
La vista posee posee tanto un objeto de la clase Controlador, como de la clase Modelo; un constructor que recibe
dichos parmetros y un mtodo que se encarga de imprimir por pantalla un enlace. Este enlace est seteando el
valor click al parmetro accion, el cual va a ser utilizado por el controlador.
Finalmente el controlador:
El controlador posee un objeto de la clase Modelo, un constructor con dicho parmetro y un mtodo que modifica el
texto dentro del modelo.
Veamos ahora cmo funcina todo en conjunto:
class Vista {
private $modelo;
private $controlador;
public function __construct(Controlador $controlador, Modelo $modelo) {
$this->controlador = $controlador;
$this->modelo = $modelo;
}
public function mostrar() {
return '<a href="holamundo.php?accion=click">' . $this->modelo->texto . '</a>';
}
}
class Controlador {
private $modelo;
public function __construct(Modelo $modelo) {
$this->modelo = $modelo;
}
public function click() {
$this->modelo->texto = 'Chau mundo';
}
}
// creamos e inicializamos un objeto de Modelo
$modelo = new Modelo();
// creamos e inicializamos un objeto del tipo Controlador y uno de Vista
// es muy importante que ambos compartan el mismo modelo
$controlador = new Controlador($modelo);
$vista = new Vista($controlador, $modelo);
// verificamos si se produjo alguna accin
if (isset($_GET['accion'])) $controlador->{$_GET['accion']}();
echo $vista->mostrar();
www.nebaris.com 29
Introduccin a CodeIgniter
Como desarrollador PHP es posible que muchas veces te encuentres reescribiendo cdigo y duplicando partes en
diferentes proyectos. Son momentos como esos, en los que te das cuenta que es necesario utilizar un framework
que facilite la creacin de proyectos. Hoy vamos a hablar sobre uno de los frameworks ms utilizados dentro del
mundo PHP: CodeIgniter.
Qu es CodeIgniter?
CodeIgniter es un framework para programadores que utilizan PHP. Su objetivo es permitir desarrollar proyectos
de manera ms rpida que hacindolos desde cero, otorgando libreras que se ocupan de las necesidades
comunes, como tambin proveer interfase simple y estructura lgica a dichas libreras. Permite centrarte en el
proyecto minimizando la cantidad de cdigo necesario.
Beneficios de utilizar CodeIgniter:
Es muy liviano (pesa apenas ms de 1 mb)
Posee muy buen desempeo
Otorga compatibilidad con diferentes versiones de PHP
Requiere mnima configuracin
No requiere el uso de la lnea de comandos
Curva de aprendizaje muy suave
Posee muchsima documentacin
Construido con orientacin a objetos
Utiliza la metodologa MVC
Su estructura de carpetas es muy simple
Hoy vamos a crear una aplicacin muy simple que muestre las novedades de un comercio. Pero antes de pasar al
cdigo, me gustara explicar un poco sobre MVC.
Qu es MVC?
MVC es una metodologa de programacin, la cual se centra en mantener la lgica de negocio de una aplicacin
separada de la presentacin (lo que los usuarios ven en el navegador), diferenciando tres capas que se
interconectan:
El modelo (M) que representa los datos. Las clases que se encuentren dentro de la capa del modelo,
contendrn funciones que interaccionarn con una base de datos.
La vista (V) es la presentacin. Una vista generalmente es una pgina, pero puede ser tambin un fragmento
de ella, como un encabezado o pie de pgina.
El controlador (C) que se encarga del trabajo duro. Su funcin es la de ser el intermediario entre el modelo y
la vista.
El separar un proyecto de esta manera, significa que cada capa hace un trabajo eficiente; los lmites entre ellas
estn bien definidos y el mantenimiento se hace ms simple. Tambin significa que mltiples vistas y controladores
pueden utilizar el mismo modelo, lo cual ayuda a la escalabilidad.
Este es apenas un acercamiento al patrn MVC, pero es suficiente para poder empezar a trabajar con CodeIgniter.
www.nebaris.com 30
Ejemplo
Antes que nada, tenemos que descargar CodeIgniter a nuestro equipo, visitando esta pgina:
http://ellislab.com/codeigniter/. Nos descargaremos un archivo zip, que tenemos que extraer. Tomamos la carpeta
descomprimida y la colocamos en nuestra raz web (si usamos Xampp: htdocs/). La renombramos para que tenga
un nombre ms simple, por ejemplo: "ci". Dentro de la carpeta vamos a quitar los archivos que no nos hacen falta
hasta que nos quede la siguiente estructura:
application/
system/
index.php
Vamos a ver la pgina para verificar que todo est correcto, entrando a localhost/ci
Controladores
Si entramos en la carpeta "application" vamos a ver que dentro hay varios directorios. Los ms importantes ahora
para nuestro ejemplo son:
config
controllers
models
views
Como podemos adivinar, dentro de la carpeta "controllers" vamos a crear los controladores para nuestro proyecto.
Empezaremos con un controlador llamado "Novedades". Para eso creamos un nuevo archivo dentro de esta
carpeta llamado novedades.php y creamos una clase que derive de CI_Controller:
<?php
class Novedades extends CI_Controller {
www.nebaris.com 31
Navegamos a la siguiente direccin localhost/ci/index.php/novedades y observamos que se muestra el texto que
acabamos de crear.
Mejorar la URL
En base al ejemplo anterior, vemos que dentro de la URL pasamos por el archivo index.php. No queda bien eso,
por lo que vamos a quitarlo para poder acceder directamente a nuestro controlador. Para eso vamos a utilizar un
archivo .htaccess (pods leer este artculo para aprender ms sobre ellos). Lo tenemos que crear en la ruta de
nuestra aplicacin con el siguiente cdigo:
Ahora podemos navegar directamente a localhost/ci/novedades
Vistas
Las vistas son donde se pone el cdigo HTML. Vamos a crear dentro de la carpeta "views" un archivo llamado
lista-de-novedades.php. Y vamos a poner el siguiente cdigo:
Ahora vamos a modificar el controlador, para que llame a la vista.
public function index()
{
echo 'Novedades';
}
}
?>
Options FollowSymLinks
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
<IfModule !mod_rewrite.c>
ErrorDocument 404 /index.php
</IfModule>
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Nuestro negocio - Novedades</title>
</head>
<body>
<h1>Novedades</h1>
</body>
</html>
public function index()
{
www.nebaris.com 32
Volvemos a visitar localhost/ci/novedades y podemos ver que ahora se llama a la vista.
Rutas
Si queremos que este controlador sea la pgina por defecto, tenemos que indicarlo en el archivo de configuracin
de rutas. Abrimos el archivo "application/config/routes.php" y buscamos la siguiente lnea
Y cambiamos welcome por noticias.
Pasar datos a una vista
Muy pocas veces vamos a tener una pgina HTML esttica en nuestros proyectos. En el patrn MVC tenemos que
manejar los datos en el modelo, leerlos en el controlador y generar el cdigo HTML en la vista. Eso significa que el
controlador tiene que de alguna forma enviarle datos a la vista, para que esta pueda mostrarlos. Vamos a ver un
ejemplo de como enviarle datos, antes de hablar sobre el modelo.
Primero creamos un array con un dato cualquiera.
Y luego al momento de cargar la vista, le pasamos el arreglo.
Ahora lo mostramos en la vista.
Recargamos la pgina para ver el cambio.
Base de datos
Vamos a crear un modelo con una funcin que lea las novedades de nuestro comercio, las cuales se guardan en
una tabla en la base de datos. Primero ejecutamos el script SQL para la tabla.
$this->load->view('lista-de-novedades');
}
$route['default_controller'] = "welcome";
$data['hola'] = 'Hola mundo';
$this->load->view('lista-de-novedades', $data);
<h1>Novedades</h1>
<?php
echo $hola
?>
...
CREATE TABLE IF NOT EXISTS `novedades` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`titulo` varchar(50) DEFAULT NULL,
`descripcion` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
www.nebaris.com 33
Conexin
Para poder conectarnos con esta tabla, tenemos que indicarle a CodeIgniter cmo hacerlo. Vamos al archivo
"application/config/database.php" y buscamos las siguientes lneas:
Rellenamos los campos con los datos de nuestra base. Luego vamos a indicar que queremos que esta base se
cargue automticamente, para que siempre est disponible. Vamos al archivo "application/config/autoload.php" y
modificamos la lnea:
Por esta otra:
Modelos
Dentro de la carpeta "application/models" vamos a crear un archivo llamado "noticias.php". Dentro creamos una
clase que tiene que derivar de CI_Model. Le definimos como propiedad la tabla a la que queremos acceder y
establecemos una funcin de lectura para obtener los datos; estos se pasarn en forma de un arreglo asociativo.
Pasndole a la vista el modelo
Ya vimos que podemos pasarle datos a la vista, ahora vamos a pasarle directamente el modelo. Para eso,
tenemos primero que cargar el modelo, leer los datos y finalmente cargar la vista y entregarle los datos. Entonces
modificamos la funcin index() del controlador.
INSERT INTO `novedades` (`id`, `titulo`, `descripcion`) VALUES
(1, 'Nuevo local', 'Hoy festejamos la apertura de nuestro nuevo local'),
(2, 'Extendemos nuestra franquicia', 'Quermos comentarles que a partir de hoy...'),
(3, 'Nos expandimos', 'Empezamos a exportar nuestros artculos a toda Latino Amrica...');
$db['default']['hostname'] = 'localhost';
$db['default']['username'] = '';
$db['default']['password'] = '';
$db['default']['database'] = '';
$autoload['libraries'] = array();
$autoload['libraries'] = array('database');
<?php
class Noticias extends CI_Model {
private $_tabla = 'novedades';
public function read()
{
return $this->db->get($this->_tabla)->result_array();
}
}
?>
www.nebaris.com 34
Por ltimo, modificamos la vista para iterar los datos obtenidos y mostrarlos.
Recargamos la pgina y vemos el resultado.
public function index()
{
$this->load->model('noticias');
$data['noticias'] = $this->noticias->read();
$this->load->view('lista-de-novedades', $data);
}
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Nuestro negocio - Novedades</title>
</head>
<body>
<h1>Novedades</h1>
<?php
foreach ($noticias as $noticia) {
echo "<p><strong>".$noticia['titulo']."</strong></p>";
echo "<p>".$noticia['descripcion']."</p>";
}
?>
</body>
</html>
www.nebaris.com 35

Potrebbero piacerti anche