PHP中的类方法访问控制

时间:2012-12-03 15:44:45

标签: php oop

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

谢谢!

3 个答案:

答案 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