使用指定接口以外的其他方法时,此代理类将引发异常:
class RestrictInterfaceProxy
{
private $subject;
private $interface;
private $interface_methods;
function __construct($subject, $interface)
{
$this->subject = $subject;
$this->interface = $interface;
$this->interface_methods = get_class_methods($interface);
}
public function __call($method, $args)
{
if (in_array($method, $this->interface_methods)) {
return call_user_func([$this->subject, $method], $args);
} else {
$class = get_class($this->subject);
$interface = $this->interface;
throw new \BadMethodCallException("Method <b>$method</b> from <b>$class</b> class is not part of <b>$interface</b> interface");
}
}
}
然后你应该改变你的
C
施工单位:
class C
{
private $a;
public function __construct(A $a)
{
// Just send the interface name as 2nd parameter
$this->a = new RestrictInterfaceProxy($a, 'A');
}
public function doManyThing()
{
$this->a->doSomething();
$this->a->doBOnlyThing();
}
}
测试:
try {
(new C(new B()))->doManyThing();
} catch (\Exception $e) {
die($e->getMessage());
}
输出:
方法
多联机
从
乙
类不是
一
接口
上一个答案:
我误解了OP的问题。如果一个类的方法不是它实现的接口所具有的方法,则该类将引发异常。
把它当作
$proxified = new InterfaceProxy(new Foo);
class InterfaceProxy
{
private $subject;
/* In PHP 7.2+ you should typehint object
see http://php.net/manual/en/migration72.new-features.php */
function __construct($subject)
{
$this->subject = $subject;
// Here, check if $subject is complying
$this->respectInterfaces();
}
// Calls your object methods
public function __call($method, $args)
{
if (is_callable([$this->subject, $method])) {
return call_user_func([$this->subject, $method], $args);
} else {
$class = get_class($this->subject);
throw new \BadMethodCallException("No callable method $method at $class class");
}
}
private function respectInterfaces() : void
{
// List all the implemented interfaces methods
$interface_methods = [];
foreach(class_implements($this->subject) as $interface) {
$interface_methods = array_merge($interface_methods, get_class_methods($interface));
}
// Throw an Exception if the object has extra methods
$class_methods = get_class_methods($this->subject);
if (!empty(array_diff($class_methods, $interface_methods))) {
throw new \Exception('Class <b>' . get_class($this->subject) . '</b> is not respecting its interfaces', 1);
}
}
}
我得到了以下答案的帮助:
当然,这个解决方案是定制的,但是由于PHP本身无法解决这个问题,我认为值得自己尝试构建这个解决方案。