Вообще, в далекой перспективе мне хотелось бы изменить синтаксис псевдовызовов методов моделей и писать так: $this->ModuleUser->getUsersByFilter(); Но это сугубо личные предпочтения
По причине выходного дня и наличия немногого свободного времени — предлагаю экспромт на эту тему. Опять же не стоит относиться к предложению как к готовому решению — это всего лишь способ — может и вообще ненужный и не к месту (
Хочу обращаться к модулям и их методам так:
$aReturn = $this->modules->topic->getTopicsByFilter($aFilter,$iPage,$iPerPage,array('user','blog'));
А не так:
$aReturn = $this->Topic_GetTopicsByFilter($aFilter,$iPage,$iPerPage,array('user','blog'));
Вообщем в голову пришла мысль не менять существующий уклад в LS, а просто добавить проксирующие свойства, которые просто передавали бы данные в псевдовызовы. Организовать альтернативную форму записи – и вот что из этого получилось.
Задача: Убрать магию из вызовов методов модулей.
Что это даст: Автокомплит, PHPDoc, повысит читабельность кода, сделает возможным использовать инспектора кода
Решение
Без хака, конечно же, не обошлось, но изменения были внесены минимальные:1. В класс LsObject добавлено свойство $modules, а конструктор класса – инициализация этого свойства – так:
abstract class LsObject {
public $modules;
public function __construct() {
$this->modules = new modules();
}
Сам класс modules прост и незамысловат – он получает лишь модуль по его имени:
class modules {
public function __get($sName) {
return Engine::getInstance()->getModule(ucwords($sName).'_')[0];
}
}
2. В классе Module от которого наследуются все модули в конструктор добавим вызов родительского конструктора:
final public function __construct(Engine $oEngine) {
parent::__construct(); // <-- здесь
$this->oEngine = $oEngine;
}
3. Тоже в конструктор сущности
public function __construct($aParam = null) {
parent::__construct();// <-- здесь
$this->_setData($aParam);
$this->Init();
}
Теперь можно обращаться к методам модуля через данное свойство, так (это пример из плагина Categories — и он работает):
$aReturn = $this->modules->topic->getTopicsByFilter($aFilter,$iPage,$iPerPage,array('user','blog'));
И теперь доступен автокомплит и phpDoc!
Плагины
Для них на самом деле рабоает такой код:Но это не очень красиво — внесем некоторые правки в файл класса LsObject^
class modules {
private $sPluginName = "";
public function __construct($sPluginName="") {
$this->sPluginName = 'Plugin' . ucwords($sPluginName) . '_';
}
public function __get($sName) {
return Engine::getInstance()->getModule(
(($this->sPluginName=='Plugin_')?'':$this->sPluginName) . ucwords($sName).'_')[0];
}
}
class plugins {
private $modules;
public function __get($sName) {
$this->modules = new modules($sName);
return $this;
}
}
/**
* От этого класса наследуются все остальные
*
* @package engine
* @since 1.0
*/
abstract class LsObject {
public $modules;
public $plugins;
public function __construct() {
$this->modules = new modules();
$this->plugins = new plugins();
}
// Здесь родной метод __call, но я его не указал
}
Это позволяет обращаться к модулям плагинов так:
Но здесь не работает автокомплит, для этих целей создадим в директории плагина файл, единственной целью которого будет доставлять возможность автокомплита и PHPDoc — вот содержимое этого файла:
<?php
die();
class plugins {
/**
* Плагин функционала категории для блогов и формировщик главной
* @var PluginCategories_ModuleCategories
*/
public $categories;
}
class modules {
/**
* Модуль управления категориями блогов
* @var PluginCategories_ModuleCategories
*/
public $categories;
}
Теперь автокомплит и документация доступна:
Заметьте — для свойства plugins автокомплит показывает перечень всех установленных плагинов (если они работают через проксирующие методы),а PHPDoc документацию по модулю и методам модуля :)
1) По идее должна увеличиться общая скорость отработки кода, т.к. вызов через «магию» — это все ж довольно ресурсоемкая операция, а таких вызовов в коде немерянно.
2) Появляется возможность передачи параметров по ссылке, чего иногда мне лично не хватало. Например:
Вот такой вызов ничего не вернет в $iCount:
А в Вашей реализации, похоже, сработает как надо:
Хотелось бы указать, что минусы тоже есть, например маппер (и вообще все наследники LsObject) получают возможность обращаться к модулям — ломается архитектура, но это все объигрывается…
Этот вызов в текущей реализации отработает в любом компоненте — сущность, маппер и т.д. Или речь о чем-то другом?
Но дополню: если и внедрять подобную реализацию, то я бы предложил чуть-чуть иной подход, а именно вместо:
реализовать что-нибудь типа:
Возможно, не так красиво, но есть важное преимущество: мы явно указываем, что не к свойству текущего объекта обращаемся, а именно к модулю. И если даже какой-то новичок программер, не въехав в нюансы, создаст экшен в котором по ему ведомой логике объявит свойство $modules — он напрочь сломает вашу реализацию, а в моем варианте все будет работать.
Так получается очень естественно и более понятно. Полностью согласен. попробую реализовать так.
Про наследников — это я с LS спутал. Там LsObject не содержит __call метода.
Но надо смотреть, удастся ли сделать так, чтоб подружить с автокомплитом и PHPDoc, ибо это несомненно большой плюс для разработчиков, использующих умные IDE