Я работаю над библиотекой, у которой есть довольно много классов, которые все спрятаны центральным классом. Этот центральный класс должен вызывать определенные методы для других классов для целей настройки / конфигурации. Эти методы должны быть общедоступными, чтобы центральный класс мог их вызывать, но я не хочу, чтобы пользователи вызывали эти методы (поскольку это может вызвать нежелательное поведение).
Одно из предложений, сделанное моим другом, состояло в том, чтобы использовать конструктор с параметрами, которые могут быть настроены во время строительства. Для целей этой библиотеки это невозможно. Рассматриваемые классы предназначены для расширения, и я не хотел навязывать какие-либо странные требования к параметрам конструктора, если пользователи хотят иметь свои собственные конструкторы. Еще сложнее то, что некоторая информация, используемая для конфигурации, недоступна для пользователя. Я должен был бы сделать его доступным для пользователя и верю, что он вернет его в соответствующие классы во время строительства.
В настоящее время мое решение состоит в том, чтобы придать этим методам что-то и отметить пользователям не вызывать методы с указанным префиксом. Это «гибкий», чтобы позволить мне добавлять более ограниченные методы, но он все же делает предположение, что пользователь будет следовать моим инструкциям. Это также не самые элегантные решения.
Мне было интересно, есть ли способ ограничить эти методы. Я подумал о добавлении в них строки, которая проверяет, был ли это центральный класс, вызывающий их, но это тоже не похоже на лучшее решение.
Изменить: я должен объяснить цель этой архитектуры. Каждый класс выполняет определенную задачу в стеке операций. Задача центрального класса состоит в том, чтобы командовать одним классом выполнять свою задачу, собирать результаты и распределять результаты другим классам, которые в них нуждаются. Затем класс переходит к следующему классу и делает то же самое. Как выполняются задачи, зависит от расширенного класса. Методы, которые я хочу ограничить, – это те, которые помогают в диспергировании результатов. Надеюсь, что мои намерения станут более ясными.
Все зависит от роли вашего центрального класса. Из вашего описания это похоже на спулер или планировщик. Если буферизованные объекты фактически созданы этим центральным классом, вы можете скрыть объекты от клиента, сделав эти объекты частными, а затем создайте заглушки в центральном объекте, что позволяет клиенту вызывать функции, которые вы разрешаете.
Например (концептуальный код, на самом деле, не может компилироваться)
class HiddenSubClass { public function MyFunc() { echo "hello"; } } class CentralClass { private $obj; function __construct() { $obj=new HiddenSubClass(); } function SubClassMyFunc () { $obj->MyFunc(); } }
Клиент имеет только объект CentralClass и, следовательно, может вызывать только SubClassMyFunc, но не MyFunc. Недостатком этого является то, что это также скроет объектно-ориентированную структуру библиотеки от клиента, что может быть или не быть желательным.
Если, однако, объекты создаются клиентом, а затем передаются вашему центральному классу, вы можете сделать это очень мало, чтобы владелец объекта (клиент) делал с ним все, что захочет. Клиент может вызывать все, что может сделать ваш центральный класс. Затем вам может потребоваться переместить код, который вы хотите защитить из указанного класса, либо в «вспомогательные классы», либо в сам центральный класс.
Изменить: если вы хотите «взломать» его, это будет один подход (хотя я не рекомендую его, потому что он довольно вонючий):
Имейте «секретную тайну» в своем центральном классе.
class CentralClass { private $MySecret=42; function IsValidSecret($anumber) { return ($anumber==$this->MySecret); } }
Теперь центральный класс может передать $ MySecret в качестве параметра, когда он вызывает определенную «защищенную» функцию на буферизованных объектах. Если CentralClass является одиночным, буферный объект может вызывать этот синглтон, чтобы проверить, правильно ли переданный секрет. Если CentralClass не является одиночным, вам также придется передать этот объект.
class MySpooledObject { function SuperSecretFunction ($asecret) { if (!$CentralSingleton->isValidSecret($asecret)) { die(); } } function SuperSecretFunction2 ($acentralobject,$asecret) { if (!$acentralobject->isValidSecret($asecret)) { die(); } } }
Есть много вариантов этого. Центральный класс мог установить внутренний флаг перед вызовом метода объекта и сбросить его после его возврата. В этом случае объект может запросить центральный класс, если этот флаг установлен, и секрет не должен передаваться. Вам все равно понадобится $ acentralobject, если только он не является синглом.