базовый, рабочий пример:
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 не вариант ...