Наличие опции настраиваемых классов, но унифицированное имя класса

Предположим, что вы создаете веб-приложение, которое будет представлять собой упакованный продукт в один прекрасный день, тот, который пользователи захотят расширить и настроить.

Он поставляется с базовой библиотекой, состоящей из файлов PHP, содержащих классы:

/library/ /library/frontend.class.php /library/filesystem.class.php /library/backend.class.php 

Теперь предположим, что вы хотите сохранить чистое ядро, которое пользователи не могут исправлять. Тем не менее, вы хотите, чтобы пользователь мог настроить каждую гайку и болт, если это необходимо.

Моя нынешняя идея – создать механизм автозагрузки, который, когда экземпляр класса создается, сначала загружает ядро:

 /library/frontend.class.php 

то он переключается на каталог user и смотрит, есть ли одноименное имя:

  /user/library/frontend.class.php 

если он существует, он также включает это.

Очевидно, что пользователь должен включать определение класса, которое расширяет определение в ядре.

Теперь мой вопрос: как мне создать такой класс? В конце концов, я всегда могу быть уверен, что есть определение:

 class frontend_core 

но я не могу быть уверен, что есть

 class frontend_user extends frontend_core 

Тем не менее, я хотел бы иметь возможность полагаться и создавать экземпляр одного имени класса , независимо от того, было ли пользовательское расширение для класса или нет.

Есть ли умный способ, идея или образец, как достичь этого?

Конечно, я мог бы написать простую вспомогательную функцию фабрики, которая сначала ищет класс user а затем для core класса и возвращает инициализированный объект, но я бы очень хотел, чтобы это было максимально простым и простым, поскольку, как я уже сказал, это будет упакованный продукт.

Я ищу умный трюк или шаблон, который использует как мало кода, и вводит как можно больше новых функций.

Почему бы вам не следовать подходу, используемому Propel? Вы генерируете базовые классы и уже предоставляете пустой класс пользователя (расширяющий базовый класс), где ваши пользователи могут помещать свои переопределения / конкретные детали реализации, а в вашем коде вы всегда ссылаетесь на классы пользователя. Поэтому в основном вы просто используете инверсию описанной вами логики.

Если приведенное выше объяснение не ясно, посмотрите http://propel.phpdb.org/trac/wiki/Users/Documentation/1.4/QuickStart#a6.UsingtheGeneratedSQLandOMFiles и сгенерируйте код для небольшой базы данных. Базовые классы находятся в папке om, (по умолчанию пустые) классы пользователей находятся в корневой папке.

Я бы использовал крючки в ядре, поэтому пользователям не нужно взламывать ядро, но они все еще могут расширять ядро ​​с помощью крючков

Я хотел бы использовать конструктор основного класса для определения загружаемого пользовательского класса, а затем реализовать фабричный метод в основном классе для генерации экземпляров пользовательского класса. Сделав конструктор защищенного класса пользователя, а класс пользователя расширяет основной класс, вы можете быть уверены, что код в другом месте не может создать экземпляр класса пользователя.

C.

Я думаю, что это сложнее с единственным именем файла, когда вы также хотите использовать наследование. В основном class user_frontend extends core_frontend должен знать, где найти оба класса. Оба должны быть включены.

Если вы просто хотите создать new Frontend вы можете использовать class_alias class_alias чтобы указать Frontend на используемый основной класс. Ниже 5.3. вы можете использовать ServiceFinder, который знает, как сопоставить имена сервисов в классах, а затем получить Frontend с помощью $service->get('frontend') или использовать инфраструктуру Injection Dependency .

Редактировать Я удалил код Loader, указанный ранее, потому что он страдал именно от этой проблемы.

У вас может быть класс загрузчика, который будет решать, какой класс для экземпляра:

 Loader::instance()->load('Frontend')