Стратегия решит проблему.
Каждый форматтер - отдельный класс. Все они реализуют один интерфейс.
Получать их можно через фабрику, в которой реализован кэш экземпляров объектов.
<?php
class FormatterFactory
{
const TRAFFIC = 1;
const CONVERSION = 2;
protected static $cache = array();
public static function get($formatterId)
{
if (static::isInCache($formatterId)) {
return static::getFromCache($formatterId);
}
$formatter = static::createNewFormatter($formatterId);
static::setToCache($formatterId, $formatter);
return static::getFromCache($formatterId);
}
protected static function createNewFormatter($formatterId)
{
switch ($formatterId) {
case static::TRAFFIC:
$object = new TrafficFormatter();
break;
case static::CONVERSION:
$object = new ConversionFormatter();
break;
default:
throw new Exception("Unknown formatterId: {$formatterId}");
break;
}
return $object;
}
protected static function isInCache($formatterId)
{
return isset(static::$cache[$formatterId]);
}
protected static function setToCache($formatterId, FormatterInterface $formatter)
{
static::$cache[$formatterId] = $formatter;
}
protected static function getFromCache($formatterId)
{
return isset(static::$cache[$formatterId]) ? static::$cache[$formatterId] : null;
}
}
interface FormatterInterface
{
public function format($data);
}
class TrafficFormatter implements FormatterInterface
{
public function format($data)
{
return $data . 'traffic';
}
}
class ConversionFormatter implements FormatterInterface
{
public function format($data)
{
return $data . 'conversion';
}
}
class Formatter
{
/**
* @param FormatterInterface[] $formatters
* @param string $data
* @return string
*/
static public function format($formatters, $data)
{
foreach ($formatters as $formatter) {
$data = $formatter->format($data);
}
return $data;
}
}
$data = 'hello';
$data = Formatter::format(array(
FormatterFactory::get(FormatterFactory::TRAFFIC),
FormatterFactory::get(FormatterFactory::CONVERSION),
), $data);
echo $data; // hellotrafficconversion