Interfaces y clases abstractas en PHP

0 comentarios

En este post explicaremos que son las interfaces y las clases abstractas, y para que utilizaremos cada una de ellas.

Interfaces

Las interfaces de objetos permiten crear código con el cual especificamos qué métodos deben ser implementados por una clase, sin tener que definir cómo estos métodos son manipulados. Las interfaces son definidas utilizando la palabra clave interface, de la misma forma que con clases estándar, pero sin métodos que tengan su contenido definido. Todos los métodos declarados en una interfaz deben ser public, ya que ésta es la naturaleza de una interfaz.

Por lo general, utilizaremos las interfaces cuando queramos asegurarnos de que una clase implemente una serie de métodos. Veamos un ejemplo:

// Declarar la interfaz 'iTemplate'
interface iTemplate {
    public function setVariable($name, $var);
    public function getHtml($template);
}

// Implementar la interfaz
// Ésto funcionará 
class Template implements iTemplate {
    private $vars = array();
  
    public function setVariable($name, $var) {
        $this->vars[$name] = $var;
    }
  
    public function getHtml($template) {
        foreach($this->vars as $name => $value) {
            $template = str_replace('{' . $name . '}', $value, $template);
        }
 
        return $template;
    }
}

// Ésto no funcionará
// Error fatal: La Clase BadTemplate contiene un método abstracto
// y por lo tanto debe declararse como abstracta (iTemplate::getHtml)
class BadTemplate implements iTemplate {
    private $vars = array();
  
    public function setVariable($name, $var) {
        $this->vars[$name] = $var;
    }
}

Clases abstractas

Mientra que las interfaces sólo nos permiten compartir comportamientos entre objetos no relacionados, las clases abstractas permiten limitar y/o definir con precisión las capacidades de cada objeto. No se puede instanciar directamente a una clase abstracta, sino que habrá que crear otra clase que herede de esta (usando extends) y desde esta se podrán realizar las operaciones sobre los métodos o parámetros de la clase abstracta. En una clase abstracta se pueden definir métodos públicos, que serán accesibles desde las clases heredadas sin necesidad de sobreescribirlas.

Veamos un ejemplo de abstracción de clases:

abstract class AbstractClass
{
    // Forzando la extensión de clase para definir este método
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // Método común
    public function printOut() {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";

En este ejemplo podemos ver como las clases ConcreteClass1 y ConcreteClass2 extienden de AbstractClass y se llama al método abstracto printOut() para mostrar el resultado.

Referencias

Lambda functions y closures en PHP

0 comentarios

Con la versión de PHP 5.3, aparte de los namespaces, otra de las funcionalidades más importantes que se añadieron fue el soporte a las funciones anónimas y los closures. En este post voy a explicar un poco que es cada cosa y como podemos utilizarlo.

Lambda Functions

Las funciones Lambda, (o funciones anónimas), simplemente son aquellas funciones que no tienen nombre. Son muy utilizadas en lenguajes como Javascript. La forma de declarar una función anónima sería la siguiente:

$c = function($a, $b) {
    return sqrt(pow(a, 2) + pow(b, 2));
}

echo $c;

De esta manera, vemos que estamos guardando en $c una referencia a la función anónima. Ahora la pregunta, ¿para que utilizaremos las funciones lambda?. Este tipo de funciones son sobretodo útiles para utilizar callbacks en nuestros métodos. Podemos crear algo parecido a esto:

function greet($value, $callback) {
    echo $callback($value);
}

greet(’ZonaDev’, function($name) {
    return "Hello, $name";
}); 

En este ejemplo, primero definimos la función greet, con dos parámetros, de los cuales el segundo será un callback (una función anónima). En el momento de llamar a la función greet, vemos como le pasamos el nombre y una función anónima que se ejecutará cuando llamamos a echo $callback($value);

Closures

Vamos a ir ahora con las closures, que no son más que funciones anónimas. La única diferencia, es que estas necesitan conocer el valor de alguna variable que se encuentra fuera de la función anónima para realizar sus procesos. Para poder pasarle a una closure una variable externa que utilizará, vamos a utilizar use, vayamos con un ejemplo:

//Simple math class 
class Math
{
    function  __construct($a) {
        $this->a =$a;
    }
    //Returns a closure
    function mul()
    {
        //We can't directly use $this inside closure
        $self = $this;
        return function($n) use($self) {
            return $n*$self->a;
        };
    }
}
$math = new Math(5);
$mul = $math->mul();
echo $mul(4); //Output : 20

En este caso, vemos como dentro de mul creamos una closure y le pasamos una instancia de $this.

Hasta aquí una explicación breve de lo que son las funciones anónimas y como podemos utilizarlas, pronto empezaremos con los patrones de diseño.

Referencias

Namespaces en PHP

0 comentarios

Para empezar, un poco de teoría sobre que son los namespaces (o nombres de espacio). Con la salida de la versión de PHP 5.3, una de las novedades más importantes que se incorporaron fué la posibilidad de utlizar namespaces, como ya se podían hacer en otros lenguajes de programación como eran C, C++ y Java, por ejemplo.

Para entender que es un namespace, podemos recurrir a la definición que encontramos en la propia Wikipedia: Un namespace es "un contenedor abstracto que agrupa de forma lógica varios símbolos e identificadores" y los utilizaremos básicamente, para estructurar mejor nuestro código fuente.

Antes de que salieran los namespaces, en PHP todas las clases, constantes y funciones cargadas se ubican en un espacio global.

Para explicar el uso de namespace, crearé un supuesto modelo desde el cual accederemos después mediante el controlador:

namespace Users\Model;

class UserModel {

    private String $nick = '';

    public function getNick() {
        return $this->nick;
    }

    public function setNick($p_nick) {
        $this->nick = $p_nick;
    }
}

En este ejemplo, vemos como un namespace puede tener sub-namespaces. "Model", es un sub-namespace dentro de "Users"

Una vez definida una clase en el namespace "Users\Model", podremos acceder a ella mediante otra clase, en este caso un controlador. Hay que recordar que, en caso de ser necesario hacer un include o un require, tendremos que hacerlo SIEMPRE después de la declaración del namespace.

namespace Users\Controller;
require_once 'users_model.php';

$bd = new \Users\Model\UserModel();
$bd->setNick('ZonaDev');

var_dump($bd->getNick());

En el caso de que la clase controlador y la clase modelo se encontraran en el mismo nombre de espacio, no haría falta añadir la ruta del nombre de espacio en la declaración.

También es interesante saber, que si vamos a utilizar mucho los objetos ubicados en un mismo namespace, podemos ahorrarnos bastante trabajo haciendo uso de la sentencia use, que además nos permite definir un alias para las clases. Aquí van algunos ejemplos:

namespace Users\Controller;
use Users\Model;
require_once 'users_model.php';

$bd = new UserModel();
$bd->setNick('ZonaDev');

var_dump($bd->getNick());

Usando alias:

namespace Users\Controller;
use Users\Model\UserModel as User;
require_once 'users_model.php';

$bd = new User();
$bd->setNick('ZonaDev');

var_dump($bd->getNick());

Con esta pequeña introducción a los namespaces, podremos entender mucho mejor el funcionamiento de los nuevos frameworks MVC que están saliendo y hacen uso de ellos, como es el ejemplo de Symfony2 y el inminente Zend Framework 2, además de motivarnos a utilizarlos para todo tipo de proyecto desarrollado en php.

Si quieres aprender más sobre el uso de namespaces, te recomiendo mirarte la documentación oficial de PHP en los siguientes enlaces:

Espacios de nombres (namespaces)
Usar espacios de nombres: Lo básico
FAQ: Cosas que se necesitan saber sobre los espacios de nombres

NOTA: Os recomiendo que leais el libro "Desarrollo web ágil con Symfony2" de Javier Equiluz, en el explica bastante bien que son los namespaces y como debemos utilizarnos (aplicando al entorno de Symfony2, claro).