Мне нужно организовать какой-то контроль доступа к объектным методам, когда он используется в разных контекстах (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 должен быть хорошо документирован)
Благодаря!
Вместо наследования вы можете использовать композицию через черты (введенные в 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 }
Вы можете использовать наследование здесь, например:
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
, вы возвращаете экземпляр A
который имеет только doA()
.
Вы не можете изменить класс в зависимости от того, когда и как создаются экземпляры (ну, не совсем).
Вы можете использовать хакерское обходное решение (но я бы рекомендовал против него)
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
ваш APIAClient
вернет new A()
, тогда как APIBClient
возвращает новый экземпляр класса B
При использовании типа-намека вы можете просто проверить экземпляры AB
:
public function doSomething(AB $instance) { if ($instance instanceof A) { return $instance->doB(); } return $instance->doA(); }
Или, не полагаясь на тип-намеки и проверку типов, вы всегда можете использовать одну из многих функций, таких как method_exists