简体   繁体   English

PHP中的类方法访问控制

[英]Class methods access control in PHP

I need to organize some kind of access control to object methods when it is used in different contexts (API's in my system). 当在不同的上下文(系统中的API)中使用对象方法时,我需要组织对对象方法的某种访问控制。 Here is code example: 这是代码示例:

    class A
    {
      public function doA(){}
      public function doB(){}
    }

    class APIAClient
    {
      public function getA()
      {
        return new A();
      }
    }

    class APIBClient {
      public function getA()
      {
        return new A();
      }
    }

In APIAClient object A should have both methods doA() and doB(), but in APIBClient should not have doB() method. 在APIAClient中,对象A应该同时具有doA()和doB()方法,但在APIBClient中,则不应具有doB()方法。

For now I've implemented APIBClientAProxy (which is returned by APIBCleint->getA()) 目前,我已经实现了APIBClientAProxy(由APIBCleint-> getA()返回)

   class APIBClientAProxy
   {
     private $a = new A;
     public function doA()
     {
       $this->a->doA()
     }
   }

But may be there is a better pattern for solving my problem, without using a additional proxy object for every context (ie API). 但是可能有一种更好的模式可以解决我的问题,而无需为每个上下文(即API)使用额外的代理对象。 I'm thinking about magic __call method with list of allowed methods in particular context, but magic calls is hard do document and documentation is the big point in my app (API's should be documented well) 我正在考虑魔术__call方法以及在特定上下文中允许使用的方法的列表,但是魔术调用很难做文档,而文档是我应用程序中的重点(API的文档应该很好地记录下来)

Thanks! 谢谢!

Instead of inheritance you can use composition through traits (introduced in PHP 5.4). 除了继承,您还可以通过特征使用组合(PHP 5.4中引入)。

First define traits 首先定义特征

trait A {
  public function doA() {
    // do something here
  }
}

trait B {
  public function doB() {
    // do something here
  }
}

then use those traits in your class declaration 然后在类声明中使用这些特征

class APIAClient {
  use A, B

}

class APIBClient {
  use A
}

You could use inheritance here, like this: 您可以在此处使用继承,如下所示:

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();
    }
}

This way, when you call getObj() on APIAClient, it will return an instance of B which which has both doA() and doB() . 这样,当你调用getObj()上APIAClient,它会返回一个实例B同时具有这doA()doB() However, when you call it on APIBClient , you return an instance of A which only has doA() . 但是,当在APIBClient上调用它时,您将返回A的实例,该实例仅具有doA()

You can't change the class depending on when and how it's instances are created (well, not really). 您不能根据创建实例的时间和方式来更改类(嗯,不是真的)。
You could use a hacky workaround (but I'd recommend against it) 您可以使用一种变通的解决方法(但我建议您反对)

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');
        }
    }
}

So if you pass a falsy value to the constructor of A(in your APIBClient ), doB will throw an error. 因此,如果将假值传递给A(在APIBClient )的构造函数,则doB将引发错误。 However, I'd recommend using inheritance, too: 但是,我也建议您使用继承:

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

And have your APIAClient return a new A() , whereas APIBClient returns a new instance of the B class. 并让您的APIAClient返回一个new A() ,而APIBClient返回一个B类的新实例。
When using type-hinting, you can just check for AB instances: 使用类型提示时,您只需检查AB实例:

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

Or, when not relying on type-hinting and type-checking, you can always use one of the many functions like method_exists 或者,当不依赖于类型提示和类型检查时,您始终可以使用许多方法之一,例如method_exists

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM