Symfony 1.1, la guía definitiva

2.3. Herramientas comunes

Algunas técnicas se utilizan una y otra vez en Symfony, por lo que es fácil encontrarse con ellas a lo largo de este libro y en el desarrollo de tus proyectos. Entre estas técnicas se encuentran los contenedores de parámetros parameter holders), las constantes y la carga automática de clases.

2.3.1. Contenedores de parámetros

Muchas de las clases de Symfony contienen algún contenedor de parámetros. Se trata de una forma eficiente de encapsular los atributos y así poder utilizar métodos getter y setter sencillos. La clase sfRequest por ejemplo incluye un contenedor de parámetros que se puede obtener mediante el método getParameterHolder(). Todos los contenedores de parámetros almacenan sus datos de la misma forma, como se muestra en el listado 2-14.

Listado 2-14 - Uso del contenedor de parámetros de sfRequest

$peticion->getParameterHolder()->set('parametro', 'valor');

echo $peticion->getParameterHolder()->get('parametro');
 => 'valor'

La mayoría de clases que contienen contenedores de parámetros proporcionan métodos abreviados para las operaciones de tipo get/set. La clase sfRequest es una de esas clases, ya que el código abreviado del listado 2-15 obtiene el mismo resultado que el código original del listado 2-14.

Listado 2-15 - Uso de los métodos abreviados del contenedor de parámetros de sfResponse

$peticion->setParameter('parametro', 'valor');

echo $peticion->getParameter('parametro');
 => 'valor'

El método getter del contenedor de parámetros permite la definición de un segundo parámetro que actua de valor por defecto. De esta manera, se obtiene una protección efectiva y sencilla frente a los errores. El listado 2-16 contiene un ejemplo de su uso.

Listado 2-16 - Uso de valores por defecto en las funciones de tipo getter

// El parámetro llamado 'parametro' no está definido, por lo que el getter devuelve un valor vacío
echo $peticion->getParameter('parametro');
 => null

// El valor por defecto se puede obtener con sentencias condicionales
if ($peticion->hasParameter('parametro'))
{
  echo $peticion->getParameter('parametro');
}
else
{
  echo 'valor_por_defecto';
}
 => 'valor_por_defecto'

// El siguiente método es mucho más rápido
echo $peticion->getParameter('parametro', 'valor_por_defecto');
 => 'valor_por_defecto'

Algunas clases del núcleo de Symfony utilizan un contenedor de parámetros que permite el uso de namespaces (gracias a la clase sfNamespacedParameterHolder). Si se utiliza un tercer parámetro en un getter o en un setter, ese parámetro se utiliza como namespace del parámetro y por tanto, el parámetro sólo estará definido dentro de ese namespace. El listado 2-17 muestra un ejemplo.

Listado 2-17 - Uso de un namespace en el contenedor de parámetros de sfUser

$usuario->setAttribute('parametro', 'valor1');
$usuario->setAttribute('parametro', 'valor2', 'mi/namespace');
echo $usuario->getAttribute('parametro');
 => 'valor1'
echo $usuario->getAttribute('parametro', null, 'mi/namespace');
 => 'valor2'

También es posible añadir contenedores de parámetros a tus propias clases, para aprovechar las ventajas de su sintaxis. El listado 2-18 muestra un ejemplo de cómo definir una clase con un contenedor de parámetros.

Listado 2-18 - Añadir un contenedor de parámetros a una clase

class MiClase
{
  protected $contenedorParametros = null;

  public function initialize($parametros = array())
  {
    $this->contenedorParametros = new sfParameterHolder();
    $this->contenedorParametros->add($parametros);
  }

  public function getContenedorParametros()
  {
    return $this->contenedorParametros;
  }
}

2.3.2. Constantes

Aunque pueda parecer sorprendente, el código de Symfony no incluye ninguna constante. La razón es que las constantes de PHP tienen un inconveniente: no se puede modificar su valor una vez definidas. Por este motivo, Symfony utiliza su propio objeto para almacenar la configuración, llamado sfConfig, y que reemplaza a las constantes. Este objeto proporciona métodos estáticos para poder acceder a los parámetros desde cualquier punto de la aplicación. El listado 2-19 muestra el uso de los métodos de la clase sfConfig.

Listado 2-19 - Uso de los métodos de la clase sfConfig en vez de constantes

// En vez de constantes de PHP...
define('MI_CONSTANTE', 'valor');
echo MI_CONSTANTE;

// ...Symfony utiliza el objeto sfConfig
sfConfig::set('mi_constante', 'valor');
echo sfConfig::get('mi_constante');

Los métodos de sfConfig permiten definir valores por defecto y se puede invocar el método sfConfig::set() más de una vez sobre el mismo parámetro para modificar su valor. El capítulo 5 detalla el uso de los métodos de sfConfig.

2.3.3. Carga automática de clases

Normalmente, cuando se utiliza un método de una clase o cuando se crea un objeto en PHP, se debe incluir antes la definición de esa clase.

include 'clases/MiClase.php';
$miObjeto = new MiClase();

Sin embargo, en los proyectos complejos con muchas clases y una estructura de directorios con muchos niveles, requiere mucho trabajo incluir todas las clases necesarias indicando correctamente la ruta de cada clase. Symfony incluye una función spl_autoload_register() para evitar la necesidad de los include y así poder escribir directamente:

$miObjeto = new MiClase();

En este caso, Symfony busca la definición de la clase MiClase en todos los archivos con extensión .php que se encuentran en alguno de los directorios lib/ del proyecto. Si se encuentra la definición de la clase, se incluye de forma automática.

De esta forma, si se guardan todas las clases en los directorios lib/, no es necesario incluir las clases de forma explícita. Por este motivo, los proyectos de Symfony no suelen incluir instrucciones de tipo include o require.

Nota Para mejorar el rendimiento, la carga automática de clases de Symfony busca durante la primera petición en una serie de directorios (que se definen en un archivo interno de configuración). Una vez realizada la búsqueda en los directorios, se guarda el nombre de todas las clases encontradas y su ruta de acceso en un array asociativo de PHP. Así, las siguientes peticiones no tienen que volver a mirar todos los directorios en busca de las clases. Este comportamiento implica que se debe borrar la cache de Symfony cada vez que se añade o se mueve una clase del proyecto (salvo en el entorno de desarrollo, donde no es necesario). El comando utilizado para borrar la cache es symfony cache:clear, salvo en el entorno de desarrollo, donde Symfony borra automáticamente la caché una vez cuando no encuentra una clase. El Capítulo 12 explica con detalle el mecanismo de cache y la configuración de la carga automática de clases se muestra en el capítulo 19.