当在不同的上下文(我的系统中使用API)中使用对象方法时,我需要组织某种访问控制。这是代码示例:
class A
{
public function doA(){}
public function doB(){}
}
class APIAClient
{
public function getA()
{
return new A();
}
}
class APIBClient {
public function getA()
{
return new A();
}
}
在APIAClient对象中,A应该有doA()和doB()两种方法,但在APIBClient中不应该有doB()方法。
现在我已经实现了APIBClientAProxy(由APIBCleint-> getA()返回)
class APIBClientAProxy
{
private $a = new A;
public function doA()
{
$this->a->doA()
}
}
但可能有更好的模式来解决我的问题,而不是为每个上下文(即API)使用额外的代理对象。我正在考虑使用特定上下文中允许的方法列表的魔法__call方法,但魔术调用很难做文档和文档是我的应用程序中的重点(API应该记录得很好)
谢谢!
答案 0 :(得分:4)
您可以使用通过特征组合(在PHP 5.4中引入)而不是继承。
首先定义特征
trait A {
public function doA() {
// do something here
}
}
trait B {
public function doB() {
// do something here
}
}
然后在你的班级宣言中使用这些特征
class APIAClient {
use A, B
}
class APIBClient {
use A
}
答案 1 :(得分:1)
你可以在这里使用继承,如下所示:
class A {
public function doA() {
// do something here
}
}
class B extends A {
public function doB() {
// do something here
}
}
class APIAClient
{
public function getObj() {
return new B();
}
}
class APIBClient {
public function getObj() {
return new A();
}
}
这样,当您在APIAClient上调用getObj()
时,它将返回B
的实例,该实例同时包含doA()
和doB()
。但是,当您在APIBClient
上调用它时,会返回A
的实例,该实例只有doA()
。
答案 2 :(得分:1)
您无法根据创建实例的时间和方式更改类(嗯,不是真的)。你可以使用hacky解决方法(但我建议反对它)
class A
{
private $_canDoB = null;
public function __construct($doB = true)
{
$this->_canDoB = !!$doB;//force bool
}
public function doB()
{
if ($this->_canDoB === false)
{
throw new LogicError('You can\'t doB');
}
}
}
因此,如果您将假值传递给A的构造函数(在APIBClient
中),doB
将抛出错误。但是,我也建议使用继承:
class AB
{
public function doA()
{
//both B and B share this method
}
}
class B
{//nothing atm
}
class A
{
public function doB()
}
让APIAClient
返回new A()
,而APIBClient
返回B
类的新实例。
使用类型提示时,您可以只需检查AB
个实例:
public function doSomething(AB $instance)
{
if ($instance instanceof A)
{
return $instance->doB();
}
return $instance->doA();
}
或者,当不依赖于类型提示和类型检查时,您总是可以使用许多函数之一,如method_exists