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.