如果适配器 class 需要类型提示怎么办? (php)
What if adapter class needs to be type hinted? (php)
这是一个基本的工作示例:
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
作为代理。所以有点臭。如何解决这个问题?删除类型提示不是一个选项...
您可以创建一个内联 class 来扩展 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();
类型提示 Test
现在应该可以工作了,因为修饰的 class 确实扩展了 Test
这是一个基本的工作示例:
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
作为代理。所以有点臭。如何解决这个问题?删除类型提示不是一个选项...
您可以创建一个内联 class 来扩展 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();
类型提示 Test
现在应该可以工作了,因为修饰的 class 确实扩展了 Test