Reputation: 1083
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 (i.e. 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!
Upvotes: 4
Views: 881
Reputation: 76395
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
Upvotes: 1
Reputation: 263
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
}
Upvotes: 4
Reputation: 42450
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()
.
Upvotes: 1