Быстрый вариант
class Sms
{
protected static $instances = [];
public static function getInstance($id = 'default')
{
$map = [
'first' => 'FirstSmsHandler',
'second' => 'SecondSmsHandler',
'default' => 'FirstSmsHandler',
];
if (!isset(self::$instances[$id])) {
if (!isset($map[$id])) {
throw new \Exception(sprintf('Unknown hadler `%s`', $id));
}
$handler = new $map[$id];
self::$instances[$id] = new self($handler);
}
return self::$instances[$id];
}
protected $handler;
public function __construct(SmsHandler $handler)
{
$this->setHandler($handler)
}
public function setHandler(SmsHandler $handler)
{
return $this->handler = $handler;
}
public function changeHandlerByName($handlerName)
{
$map = [
'first' => 'FirstSmsHandler',
'second' => 'SecondSmsHandler',
'default' => 'FirstSmsHandler',
];
if (!isset($map[$handlerName])) {
throw new \Exception(sprintf('Unknown handler `%s`', $handlerName));
}
$handler = new $map[$handlerName];
$this->setHandler($handler);
return $this;
}
public function __call($name, $arguments)
{
return call_user_func_array([$this->handler, $name], $arguments);
}
}
$sms = new Sms(new FirstSmsHandler());
$sms->changeHandlerByName($_POST['provider']);
$sms = Sms::getInstance($_POST['provider']);
$sms->getBalance();
Можно еще почитать как ларавел реализовывает контракты, сервис контайнеры и сервис провайдеры. Там через конфиг просто меняем контейнер и уже работаем с другим классом. Почитайте.