The definitive guide of Symfony 1.2

2.3. Common Instruments

A few techniques are used repeatedly in symfony, and you will meet them quite often in this book and in your own projects. These include parameter holders, constants, and class autoloading.

2.3.1. Parameter Holders

Many of the symfony classes contain a parameter holder. It is a convenient way to encapsulate attributes with clean getter and setter methods. For instance, the sfRequest class holds a parameter holder that you can retrieve by calling the getParameterHolder() method. Each parameter holder stores data the same way, as illustrated in Listing 2-14.

Listing 2-14 - Using the sfRequest Parameter Holder

$request->getParameterHolder()->set('foo', 'bar');
echo $request->getParameterHolder()->get('foo');
 => 'bar'

Most of the classes using a parameter holder provide proxy methods to shorten the code needed for get/set operations. This is the case for the sfRequest object, so you can do the same as in Listing 2-14 with the code of Listing 2-15.

Listing 2-15 - Using the sfRequest Parameter Holder Proxy Methods

$request->setParameter('foo', 'bar');
echo $request->getParameter('foo');
 => 'bar'

The parameter holder getter accepts a default value as a second argument. This provides a useful fallback mechanism that is much more concise than possible with a conditional statement. See Listing 2-16 for an example.

Listing 2-16 - Using the Attribute Holder Getter's Default Value

// The 'foobar' parameter is not defined, so the getter returns an empty value
echo $request->getParameter('foobar');
 => null

// A default value can be used by putting the getter in a condition
if ($request->hasParameter('foobar'))
{
  echo $request->getParameter('foobar');
}
else
{
  echo 'default';
}
 => default

// But it is much faster to use the second getter argument for that
echo $request->getParameter('foobar', 'default');
 => default

Some symfony core classes also use a parameter holder that support namespaces (thanks to the sfNamespacedParameterHolder class). If you specify a third argument to a setter or a getter, it is used as a namespace, and the parameter will be defined only within that namespace. Listing 2-17 shows an example.

Listing 2-17 - Using the sfUser Parameter Holder Namespace

$user->setAttribute('foo', 'bar1');
$user->setAttribute('foo', 'bar2', 'my/name/space');
echo $user->getAttribute('foo');
 => 'bar1'
echo $user->getAttribute('foo', null, 'my/name/space');
 => 'bar2'

Of course, you can add a parameter holder to your own classes to take advantage of its syntax facilities. Listing 2-18 shows how to define a class with a parameter holder.

Listing 2-18 - Adding a Parameter Holder to a Class

class MyClass
{
  protected $parameterHolder = null;

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

  public function getParameterHolder()
  {
    return $this->parameterHolder;
  }
}

2.3.2. Constants

Surprisingly, you will not find any constant in symfony. This is because constants have a major drawback in PHP: you can't change their value once they are defined. So symfony uses its own configuration object, called sfConfig, which replaces constants. It provides static methods to access parameters from everywhere. Listing 2-19 demonstrates the use of sfConfig class methods.

Listing 2-19 - Using the sfConfig Class Methods Instead of Constants

// Instead of PHP constants,
define('FOO', 'bar');
echo FOO;

// symfony uses the sfConfig object
sfConfig::set('foo', 'bar');
echo sfConfig::get('foo');

The sfConfig methods support default values, and you can call the sfConfig::set() method more than once on the same parameter to change its value. Chapter 5 discusses sfConfig methods in more detail.

2.3.3. Class Autoloading

Classically, when you use a class method or create an object in PHP, you need to include the class definition first.

include 'classes/MyClass.php';
$myObject = new MyClass();

But on large projects with many classes and a deep directory structure, keeping track of all the class files to include and their paths takes a lot of time. By providing an spl_autoload_register() function, symfony makes include statements unnecessary, and you can write directly:

$myObject = new MyClass();

Symfony will then look for a MyClass definition in all files ending with php in one of the project's lib/ directories. If the class definition is found, it will be included automatically.

So if you store all your classes in lib/ directories, you don't need to include classes anymore. That's why the symfony projects usually do not contain any include or require statements.

Note For better performance, the symfony autoloading scans a list of directories (defined in an internal configuration file) during the first request. It then registers all the classes these directories contain and stores the class/file correspondence in a PHP file as an associative array. That way, future requests don't need to do the directory scan anymore. This is why you need to clear the cache every time you add or move a class file in your project by calling the symfony cache:clear command (except in the development environment, where symfony clears the cache once when it cannot find a class). You will learn more about the cache in Chapter 12, and about the autoloading configuration in Chapter 19.