Daniel Segovia

Blog personal

Archive for diciembre, 2011

Patrón Observador

Hacer un comentario

El patrón observador es sencillo de entender y más fácil de ver cuando es necesario.
Tendremos 2 objetos, por un lado el observador y por el otro el observado.
El observador debe ver cuando el observado realiza algún cambio y tomar determinada acción.
El modelos antiguos el observador miraba constantemente al observado para ver cuando éste cambiada, el problema de éste modelo es que había que mirar constantemente al observado para ver cuando realizaba una modificación.
Con el patrón observador cambiaron un poco los roles, tenemos el mismo esquema, observador y observado, la diferente es que observador no estará “mirando” todo el tiempo a observado para ver cuando hay un cambio, sino que éste último le avisará mediante una notificación a su observador cuando haga efectivo dicho cambio.

En un ejemplo de la vida cotidiana:

- Un padre ve como su niño anda en bicicleta, él esta ateto el 100% del tiempo mirando que no se golpee, sí un accidente ocurriese el padre se enteraría al instante ya que ve lo que sucedió. Aquí vemos como el observador está monitoreando constantemente al observado.
- Un niño esta andando en bicicleta y al tener un incidente éste avisa a su padre. Aquí vemos como el observado notifica a su observador en determinado evento.

Vamos a los papeles, aquí el código
Separaremos las clases de la implementación, estará en 2 archivos, modelo.php e implementacion.php

<?php
//modelo.php
abstract class observable{
 
    protected $observadores;
 
    public function __construct(){
        $this->observadores = array();
    }
 
    public function registrarObservador($observador){
        if(!in_array($observador, $this->observadores)){
            array_push($this->observadores, $observador);
        }
    }
 
    public function eliminarObservador($observador){
        if(in_array($observador, $this->observadores)){
            $key = array_search($observador, $this->observadores);
            unset($this->observadores[$key]);
        }
    }
 
    abstract public function notificarObservador();
 
}
 
 
interface observador{
    public function notificar($remitente, $parametro);
}
 
class Usuario extends observable{
 
    public $parametro;
 
    public function __construct(){
        parent::__construct();
    }
 
    public function notificarObservador(){
        if(count($this->observadores)  > 0){
            foreach ($this->observadores as $observador){
                $observador->notificar($this, $this->parametro);
            }
        }else{
            echo "No hay observadores<br />";
        }
    }
 
    public function setParametro($value){
        $this->parametro = $value;
        $this->notificarObservador();
    }
 
    public function getParametro(){
        return $this->parametro;
    }
}
 
class Log implements Observador{
    public function notificar($remitente, $parametro){
        echo "El objeto " . get_class($remitente) . " ha cambiado la propiedad `parametro` al valor de '$parametro' a las " . date('H:i:s', time()) . "<br />";
    }
}
 
class LogDB implements Observador{
    public function notificar($remitente, $parametro){
        echo "El objeto " . get_class($remitente) . " ha guardado la propiedad `parametro` por valor de '$parametro' en la base de datos<br />";
    }
}
 
class LogEmail implements Observador{
    public function notificar($remitente, $parametro){
        echo get_class($remitente) . " notifica un cambio y ha sido enviado por mail<br />";
    }
}
?>

Vamos a dividir la explicación de modelo.php en 4

  • Definimos una clase abstracta observable, todas las clases que extiendan de ésta podrán ser observadas, también podrán registrar y eliminar observadores y deberán implementar la notificación
  • Definimos una interfaz observador, todos los observadores implementarán ésta interfaz y estarán obligadas a poseer el método notificar, sí bien éste paso podría pasarse por alto es una muy buen practica
  • Definimos la clase que va a ser observada, en este ejemplo usamos una clase llamada Usuario y ésta notificará a sus observadores cuando la propiedad método haya cambiado su valor
  • Por último definimos los observadores que implementan la interfaz y todos poseen el método notificar, aquí definimos 3 observadores, un muestra un mensaje, otro guarda en base de datos y el último da un aviso por mail

Aquí la implementación, veremos diferentes maneras en las implementaciones.

Implementación 1:

<?php
//implementacion1.php
$ob = new Usuario;
$ob->setParametro('Daniel');
echo "Parametro: " . $ob->getParametro() . "<br />";
?>
<!--resultado-->
No hay observadores
Parametro: Daniel

Implementación 2:

<?php
//implementacion2.php
$ob = new Usuario;
$ob->registrarObservador(new Log);
$ob->setParametro('Marcos');
echo "Parametro: " . $ob->getParametro() . "<br />";
?>
<!--resultado-->
El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Marcos' a las 18:40:46
Parametro: Marcos

Implementación 3:

<?php
//implementacion3.php
$ob = new Usuario;
$ob->registrarObservador(new Log);
$ob->registrarObservador(new LogDB);
$ob->registrarObservador(new LogEmail);
$ob->setParametro('Federico');
echo "Parametro: " . $ob->getParametro() . "<br />";
?>
<!--resultado-->
El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Federico' a las 18:42:08
El objeto Usuario ha guardado la propiedad `parametro` por valor de 'Federico' en la base de datos
Usuario notifica un cambio y ha sido enviado por mail
Parametro: Federico

Implementación 4:

<?php
//implementacion4.php
$ob = new Usuario;
$ob->registrarObservador(new Log);
$ob->registrarObservador(new LogDB);
$ob->registrarObservador(new LogEmail);
$ob->setParametro('Hugo');
echo "Parametro: " . $ob->getParametro() . "<br />";
 
sleep(2);
 
$ob->eliminarObservador(new LogDB);
$ob->setParametro('Diego');
echo "Parametro: " . $ob->getParametro() . "<br />";
?>
<!--resultado-->
El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Hugo' a las 18:43:45
El objeto Usuario ha guardado la propiedad `parametro` por valor de 'Hugo' en la base de datos
Usuario notifica un cambio y ha sido enviado por mail
Parametro: Hugo
El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Diego' a las 18:43:47
Usuario notifica un cambio y ha sido enviado por mail
Parametro: Diego

Written by Daniel Segovia

diciembre 28th, 2011 at 6:45 pm

Patrón de diseño Singleton

Hacer un comentario

El patrón de diseño Singleton tiene como finalidad asegurar que sólo se pueda crear una instancia de determinada clase.

Es muy común ver este patrón aplicado en las conexiones a la base de datos, no es necesario tener 10, 20 o 30 conexiones abiertas a la misma base de datos, con una es más que suficiente. Entonces cuando tenemos un proyecto en el cual varias clases harán uso de la base de datos las instancias las haremos con Singleton y esto nos asegurará tener 1 sola instancia del objeto lo cual reducirá ampliamente los consumos de memoria.

La lógica del patrón es simple, sí el objeto nunca fue creado éste es instanciado y devuelto pero sí previamente había sido instanciado el patrón devolverá objeto.

Veamos un ejemplo de un contador, noten como en la implementación se crean varias instancias del mismo objeto pero la propiedad que lleva la cuenta siempre conserva el mismo valor, naturalmente esto se debe a que el objeto siempre es el mismo.

<?php 
 
class Singleton {
   private static $instancia;
   private $contador;
   protected $cantidad;
 
 
   private function __construct(){
      echo "Primera Instancia de " . __CLASS__ . " ha sido creada\n<br/>";
      $this->contador = 0;
      $this->setCantidad(10);
   }
 
   public static function getInstance() {
      if (  !self::$instancia instanceof self) {
         self::$instancia = new self;
      }
      return self::$instancia;
   }
 
   public function getCantidad(){
      return $this->cantidad;
   }
 
   public function setCantidad($value){
      $this->cantidad = intval($value);
   }
 
   public function incrementar(){
      return $this->contador+= $this->getCantidad();
   }
 
   public function disminuir() {
      return $this->contador-= $this->getCantidad();
   }
}
?>
 
<?php
$primeraInstancia = Singleton::getInstance();
echo "Primera Instancia (+): " . $primeraInstancia->incrementar() . "\n<br/>";
echo "Primera Instancia (+): " .$primeraInstancia->incrementar() . "\n<br/>";
echo "Primera Instancia (+): " .$primeraInstancia->incrementar() . "\n<br/>";
$segundaInstancia = Singleton::getInstance();
echo "Segunda Instancia (-): " .$segundaInstancia->disminuir() . "\n<br/>";
echo "Segunda Instancia (+): " .$segundaInstancia->incrementar() . "\n<br/>";
$terceraInstancia = Singleton::getInstance();
echo "Tercera Instancia (-): " .$terceraInstancia->disminuir() . "\n<br/>";
?>

Resultado

Primera Instancia de Singleton ha sido creada
Primera Instancia (+): 10
Primera Instancia (+): 20
Primera Instancia (+): 30
Segunda Instancia (-): 20
Segunda Instancia (+): 30
Tercera Instancia (-): 20

Ahora para estar bien seguros de tener una sola instancia, debemos prevenir que el objeto sea clonado y también que sea serializado y deserializado.

Para evitar la clonación agregaremos el método __clone a nuestra clase y para la serialización el método __wakeup
Nuestra clase quedará de la siguiente manera

<?php 
 
class Singleton {
   private static $instancia;
   private $contador;
   protected $cantidad;
 
 
   private function __construct(){
      echo "Primera Instancia de " . __CLASS__ . " ha sido creada\n<br/>";
      $this->contador = 0;
      $this->setCantidad(10);
   }
 
   public static function getInstance() {
      if (  !self::$instancia instanceof self) {
         self::$instancia = new self;
      }
      return self::$instancia;
   }
 
   public function getCantidad(){
      return $this->cantidad;
   }
 
   public function setCantidad($value){
      $this->cantidad = intval($value);
   }
 
   public function incrementar(){
      return $this->contador+= $this->getCantidad();
   }
 
   public function disminuir() {
      return $this->contador-= $this->getCantidad();
   }
 
   public function __clone(){
      trigger_error("Operación Invalida: No es posible clonar una instancia de ". get_class($this) ." class.", E_USER_ERROR );
   }
 
   public function __wakeup(){
      trigger_error("Operación Invalida: No es posible deserializar una instancia de ". get_class($this) ." class.", E_USER_ERROR );
   }
}
?>

Ahora sí tenemos asegurado que la clase Singleton solo estará instanciada 1 vez.

Written by Daniel Segovia

diciembre 21st, 2011 at 1:10 pm

Patrón de diseño Factory

Hacer un comentario

El patrón de diseño factory, está basado en la instancia de objetos en tiempo de ejecución.

En pequeños proyectos no es frecuente usar éste patrón pero cuando los proyectos son grandes o trabajen muchas personas es muy común implementarlo.

Wikipedia posee una explicación perfecta

Factory Method consiste en utilizar una clase constructora (al estilo del Abstract Factory) abstracta con unos cuantos métodos definidos y otro(s) abstracto(s): el dedicado a la construcción de objetos de un subtipo de un tipo determinado. Es una simplificación del Abstract Factory, en la que la clase abstracta tiene métodos concretos que usan algunos de los abstractos; según usemos una u otra hija de esta clase abstracta, tendremos uno u otro comportamiento.

He aquí un ejemplo con varias clases para conectarse a diferentes base de datos, sin importar donde desee conectarme concentraré la instancia en una clase llamada BaseDeDatos

<?php
 
class MySQL{
  public function __construct(){
    echo "Instancio MySQL";
  }
}
 
class PostgreSQL{
  public function __construct(){
    echo "Instancio PostgreSQL";
  }
}
 
abstract class BaseDeDatos{
    public static function cargar($tipo){
        try {
            if (class_exists($tipo)) {
                return new $tipo;
            } else {
                throw new Exception("No existe la clase '$tipo'");
            }
        } catch (Exception $e) {
            echo 'Excepción capturada: ',  $e->getMessage(), "\n";
        }
    }
}
 
BaseDeDatos::cargar("MySQL");
echo "<br >";
BaseDeDatos::cargar("PostgreSQL");
echo "<br >";
BaseDeDatos::cargar("Oracle");
?>

Resultado

Instancio MySQL
Instancio PostgreSQL
Excepción capturada: No existe la clase 'Oracle'

Como resumen podemos decir que todo queda centralizado en la clase BaseDeDatos, y como puede observarse realiza una pequeña validación antes de realizar la instancia.

Written by Daniel Segovia

diciembre 21st, 2011 at 11:30 am

Introducción a patrones de diseño en PHP

Hacer un comentario

Me resulto un tanto difícil comenzar la introducción para éste capítulo, simplificar la explicación de los patrones de diseño no fue tarea sencilla, la pregunta obligada es:
¿Qué son los patrones de diseño?
Para esto busqué algunos conceptos que me guíen en la explicación y me tope en muchos lugares con la siguiente definición.
“Los patrones de diseño son el esqueleto de las soluciones a problemas comunes en el desarrollo de software”
Explicado con mis palabras, éstos ofrecen soluciones simples a problemas comunes en el desarrollo de software.
Con la gran cantidad de diseños de aplicaciones hay problemas que se repiten frecuentemente, entonces éstos responden a un cierto patrón.
Los patrones de diseño son un conjunto de buenas prácticas que pueden nos aliviarán el trabajo en muchas situaciones cuando realizamos una aplicación orientada a objetos

Sí vemos la introducción de éste capítulo como un problema y la frase que hallé como una solución ya probada podríamos decir que encontré un patrón de diseño para mi problema, a grandes rasgos éste es el concepto.

Written by Daniel Segovia

diciembre 16th, 2011 at 1:31 pm

Posted in 6.1 Introducción

Seguridad en los parámetros

Hacer un comentario

La seguridad en los parámetros es un concepto muy viejo pero es muy efectivo.
Los ataques SQL Injection son más comunes de lo que uno piensa, por ende las cadenas de texto (SQL) que enviamos al motor de la base de datos deben, como mínimo, prevenir este tipo de ataques.
La forma más común en estos ataques es cuando ingresamos valores externos a nuestro código a la base de datos, es decir un parámetro que venga por POST o GET.

Sí enviamos el siguiente query a la base

<?php
$query = "SELECT * FROM personas WHERE id = 5";
//envio el query
?>

no existe tal SQL Injection por que id = 5 será siempre id = 5 ya que esta embebido en nuestro código.

Un ejemplo diferente con una vulnerabilidad visible es el siguiente.

<?php
$query = "SELECT * FROM personas WHERE id = " . $_GET['id'];
//envio el query
?>

en este caso debemos prevenir que $_GET['id'] no contenga ningún código malicioso.

Cuando trabajamos con bases de datos Oracle tenemos a nuestro disposición la función oci_bind_by_name que realizará un blindaje sobre los parámetros, un metodología similar a stmt de mysqli.

<?php
$conn = oci_connect("usuario", "contraseña", "localhost/XE");
if (!$conn) {
    $m = oci_error();
    trigger_error(htmlentities($m['message']), E_USER_ERROR);
}
 
$sql = 'SELECT id,nombre,apellido FROM personas WHERE id = :id';
$stid = oci_parse($conn, $sql);
$id = $_GET['id'];
oci_bind_by_name($stid, ':id', $id);
oci_execute($stid);
$fila = oci_fetch_array($stid, OCI_ASSOC);
print_r($fila);
 
oci_free_statement($stid);
oci_close($conn);
?>

Written by Daniel Segovia

diciembre 1st, 2011 at 4:35 pm