4

当在不同的上下文(我系统中的 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 应该有很好的文档记录)

谢谢!

4

3 回答 3

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
}
于 2012-12-03T16:00:58.107 回答
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();
    }
}

这样,当您调用getObj()APIAClient 时,它将返回一个B同时具有doA()和的实例doB()。但是,当您调用它时,您会返回一个只有APIBClient的实例。AdoA()

于 2012-12-03T15:50:31.807 回答
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(in your APIBClient) 的构造函数,doB将引发错误。但是,我也建议使用继承:

class AB
{
    public function doA()
    {
        //both B and B share this method
    }
}
class B
{//nothing atm
}
class A
{
    public function doB()
}

并让您APIAClient返回 a new A(),而APIBClient返回该类的新实例B
使用类型提示时,您可以只检查AB实例:

public function doSomething(AB $instance)
{
    if ($instance instanceof A)
    {
        return $instance->doB();
    }
    return $instance->doA();
}

或者,当不依赖类型提示和类型检查时,您始终可以使用许多功能之一,例如method_exists

于 2012-12-03T16:05:26.900 回答