简体   繁体   中英

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). 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.

For now I've implemented APIBClientAProxy (which is returned by 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). 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)

Thanks!

Instead of inheritance you can use composition through traits (introduced in 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() . However, when you call it on APIBClient , you return an instance of A which only has 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. 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.
When using type-hinting, you can just check for AB instances:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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