Что, если класс адаптера должен быть подсказан по типу? (РНР)

Итак, основной, рабочий пример:

class Test
{
public function test()
{
return 'a';
}
}

/**
* @mixin Adapter
*/
class TestAdapter
{
/**
* @var Test
*/
private $test;

public function __construct(Test $test)
{
$this->test = $test;
}

public function __call($method, $args)
{
switch($method)
{
case 'test' :
return 'decorated: '.$this->test();
default :
throw new \Exception('Unhandled method call: '.$method);
}
}
}

$test = new Test();
$testAdapter = new TestAdapter($test);
$testAdapter->test();

Все идет нормально. Но что, если это Test кому-то нужно? Что если абстракция вступит в силу?

abstract class TestAbstract
{
public abstract function t();
}

class Test extends TestAbstract
{
public function t()
{
return 't';
}

public function test()
{
return 'test';
}
}

class WannaTest
{
public function __construct(Test $test)
{
}
}

сюда:

$test = new Test();
$testAdapter = new TestAdapter($test);
$wannaTest = new WannaTest($testAdapter); // would throw fatal!

это не сработает, так как WannaTest надеется Test,
Конечно, я мог бы продолжить TestAdapter:

class TestAdapter extends Test
{
public function t()
{
// now I cant mock it!
}
}

но в этом случае, если у меня есть 10 абстрактных методов, я должен был бы реализовать их, даже если используется только один из них. Таким образом, я не могу использовать __call либо в качестве прокси. Так что это немного вонючий. Как обойти это? Удаление typehint не вариант …

1

Решение

Вы можете создать встроенный класс, который расширяет Test и украшает метод, как вам нужно. Вот пример.

class TestDecorator //decorator sounds more appropriate
{

public static function decorate(Test $test) {
return new class($test) extends Test {
private $test;
public function __construct(Test $test) {
$this->test = $test;
}
public function test() {
return 'decorated: '.$this->test->test();
}
};

}
}
$test = new Test();
$decorated = TestDecorator::decorate($test);
echo $decorated->test();

Type-хинтинг Test теперь должен работать, так как декорированный класс действительно расширяется Test

1

Другие решения

Других решений пока нет …