У вас есть два очевидных кандидата:
Лично я (всегда) буду использовать службы с тегами ( шаблон стратегии ) для такого сценария, но все же даю примеры для каждого из них, так что вам решать.
Примечание : у вас будут дубликаты и немного некрасивого кода в вашем сервисе, если вы используете сервисный локатор, как показано ниже.
ЛОКАТОР ОБСЛУЖИВАНИЯ
interface ServiceLocatorInterface
{
public function locate(string $id);
}
-
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
class ServiceLocator implements ServiceLocatorInterface, ServiceSubscriberInterface
{
private $locator;
public function __construct(ContainerInterface $locator)
{
$this->locator = $locator;
}
public static function getSubscribedServices()
{
return [
'string_version' => StringCalculator::class,
'int_version' => IntCalculator::class,
];
}
public function locate(string $id)
{
if (!$this->locator->has($id)) {
throw new ServiceLocatorException('Service was not found.');
}
try {
return $this->locator->get($id);
} catch (ContainerExceptionInterface $e) {
throw new ServiceLocatorException('Failed to fetch service.');
}
}
}
-
class StringCalculator
{
public function calculate($value1, $value2)
{
return $value1.' - '.$value2;
}
}
-
class IntCalculator
{
public function calculate($value1, $value2)
{
return $value1 + $value2;
}
}
Использование:
class YourService
{
private $serviceLocator;
public function __construct(\App\ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
public function yourMethod()
{
/** @var StringCalculator $calculator */
$calculator = $this->serviceLocator->locate('string_version');
$result = $calculator->calculate('1', '2'); // result: 1 - 2
/** @var IntCalculator $calculator */
$calculator = $this->serviceLocator->locate('int_version');
$result = $calculator->calculate(1, 2); // result: 3
}
}
СЕРВИСНЫЕ УСЛУГИ
service:
App\Strategy\Calculator:
arguments: [!tagged calculator]
App\Strategy\StringCalculatorStrategy:
tags:
- { name: calculator }
App\Strategy\IntCalculatorStrategy:
tags:
- { name: calculator }
-
use Traversable;
class Calculator
{
private $calculators;
public function __construct(Traversable $calculators)
{
$this->calculators = $calculators;
}
public function calculate(string $serviceName, $value1, $value2)
{
/** @var CalculatorStrategyInterface $calculator */
foreach ($this->calculators as $calculator) {
if ($calculator->canProcess($serviceName)) {
return $calculator->process($value1, $value2);
}
}
}
}
-
interface CalculatorStrategyInterface
{
public function canProcess(string $serviceName): bool;
public function process($value1, $value2);
}
-
class StringCalculatorStrategy implements CalculatorStrategyInterface
{
public function canProcess(string $serviceName): bool
{
return $serviceName === 'string_version';
}
public function process($value1, $value2)
{
return $value1.' '.$value2;
}
}
-
class IntCalculatorStrategy implements CalculatorStrategyInterface
{
public function canProcess(string $serviceName): bool
{
return $serviceName === 'int_version';
}
public function process($value1, $value2)
{
return $value1 + $value2;
}
}
Использование:
class YourService
{
private $calculator;
public function __construct(\App\Strategy\Calculator $calculator)
{
$this->calculator = $calculator;
}
public function yourMethod()
{
// result: 1 - 2
$result = $this->calculator->calculate('string_version', 1, 2);
// result: 3
$result = $this->calculator->calculate('int_version', 1, 2);
}
}