CMS Eleanor - Поиск
Полная версия этой страницы: Официальный форум Eleanor CMS » Fluent interface (текучий интерфейс)
Официальный форум Eleanor CMS » Для вебмастеров и владельцев сайтов » Комната программистов
Djadka
Интересует вообще все за и против данного подхода в PHP, так же скорость работы и оптимальность? В Элеоноре данный подход не реализован, хотя в некоторых местах был бы очень даже хорош, например в шаблонизаторе.
scanread
Djadka, а подетальней можно, что это такое и с чем его едят? А то обсуждать то, о чем большинство не слыхало - не имеет смысла... Какие +/- и т.д. и т.п.?
Skyff
Ну да было бы неплохо немного информации получить.
Djadka
Википедия
Это общая информация, на данной технологии или подходе реализовано много ORM библиотек да и не только ОРМ. Где что читал и из хабры и ещё были какие то источники, везде мнение расходилось, кто к чему привык, а вот на счёт оптимальности использование и ресурсоёмкости не кто не что не сказал. Вот интересует мнение, кто с чем сталкивался.
KDesign
хм..интересно,спасибо! есть повод для размышлений,
похоже,очевидно, что нагрузка будет немного больше, чем в простом ООП.
Но, я все же за обычный ООП АПИ )
Djadka
Бытует мнение что меньше будет нагрузка... Вот надо бы мнение бывалых.
scanread, Основная идея в том, чтобы возможна была такая конструкция:
$SomeObject = (new SomeClass)->Method1($params_for_func1)->Method2($params_for_func2)->...->MethodN($params_for_funcN);


Для этого должна быть реализована примерно такая архитектура класса:


class SomeClass
{
    public function __construct()
    {
        return $this;
    }

    public function Method1($params_for_func1)
    {
        /*
            Тело функции...
        */
        return $this;
    }

   public function Method1($params_for_func2)
    {
        /*
            Тело функции...
        */
        return $this;
    }
    
    /*
        ...
        Ещё какие-либо функции
        ...
    */
    public function MethodN($params_for_funcN)
    {
        /*
            Тело функции...
        */
        return $this;
    }
}


Чуть по-подробней

Тоже удивлялся, почему Александр не использовал Fluent Interface.

Если в оригинале написано так:

$Lst=Eleanor::LoadListTemplate('table-form');
		$em=$v['values']['email'] and !$v['values']['name'];
		return self::AcMenu($handlers).($v['error'] ? Eleanor::$Template->Message($v['error']) : '')
			.'<form method="post">'
			.$Lst->begin()
			.$Lst->head($lang['reminderpass'])
			.$Lst->item(array($lang['enteryl'],Eleanor::Edit('name',$v['values']['name'],array('tabindex'=>1)).'<br /><a href="#" class="small" onclick="return ChangeLogEm()">'.$lang['fogotname'].'</a>','tr'=>array('id'=>'tr-name','style'=>$em ? 'display:none' : '')))
			.$Lst->item(array($lang['enterem'],Eleanor::Edit('email',$v['values']['email'],array('tabindex'=>2)).'<br /><a href="#" class="small" onclick="return ChangeLogEm()">'.$lang['remindname'].'</a>','tr'=>array('id'=>'tr-email','style'=>$em ? '' : 'display:none'),'descr'=>$lang['notnoem']))
			.($GLOBALS['Eleanor']->Captcha->disabled ? '' : $Lst->item(array($lang['captcha'],$GLOBALS['Eleanor']->Captcha->GetCode(),'tip'=>$lang['captcha_descr'])).$Lst-></span></span></span>item($lang['c_code'],Eleanor::Edit('check','',array('tabindex'=>3))))
			.$Lst->button(Eleanor::Button('OK','submit',array('tabindex'=>4)))
			.$Lst->end()
			.'</form><script type="text/javascript">//<![CDATA[
			function ChangeLogEm()
			{
				$("#tr-email,#tr-name").toggle();
				return false;
			}
			//]]></script>';


То с использованием "текучих интерфейсов" было бы примерно так:


$Lst=Eleanor::LoadListTemplate('table-form');
		$em=$v['values']['email'] and !$v['values']['name'];
		return self::AcMenu($handlers).($v['error'] ? Eleanor::$Template->Message($v['error']) : '')
			.'<form method="post">'
			$Lst->begin()
			->head($lang['reminderpass'])
			->item(array($lang['enteryl'],Eleanor::Edit('name',$v['values']['name'],array('tabindex'=>1)).'<br /><a href="#" class="small" onclick="return ChangeLogEm()">'.$lang['fogotname'].'</a>','tr'=>array('id'=>'tr-name','style'=>$em ? 'display:none' : '')))
			->item(array($lang['enterem'],Eleanor::Edit('email',$v['values']['email'],array('tabindex'=>2)).'<br /><a href="#" class="small" onclick="return ChangeLogEm()">'.$lang['remindname'].'</a>','tr'=>array('id'=>'tr-email','style'=>$em ? '' : 'display:none'),'descr'=>$lang['notnoem']))
			.($GLOBALS['Eleanor']->Captcha->disabled ? '' : $Lst->item(array($lang['captcha'],$GLOBALS['Eleanor']->Captcha->GetCode(),'tip'=>$lang['captcha_descr'])).$Lst->item($lang['c_code'],Eleanor::Edit('check','',array('tabindex'=>3))))
			.$Lst->button(Eleanor::Button('OK','submit',array('tabindex'=>4)))
			->end()
			.'</form><script type="text/javascript">//<![CDATA[
			function ChangeLogEm()
			{
				$("#tr-email,#tr-name").toggle();
				return false;
			}
			//]]></script>';


Хотя пример довольно неудачный, я думаю, что в некоторых случаях такую технологию было бы удобно использовать.
Djadka
Вот кто то пишет что скорость падает, кто то пишет что наоборот. Вот надо самому будет потестить. А то не понятно вообще.
Alexander
wizard993, я подумаю где в системе такое можно реализовать. Но пока не нахожу таких мест. Ваш пример с шаблонизатором неудачен. Объясняю почему. Каждый метод шаблонизатора возвращает шаблон. Тоесть строку, состояющую из кусочка будущей страницы. Fluent interface хорош для изменения состояния объектов, но при получении данных из них этим методом воспользоваться невозможно. Точнее, можно, но с костылем-финализатором:


$template=$Tplobj->title('Название')->body('тело')->foot('подвал')->GetHTML();


Финализатором здесь служил GetHTML, который в результате возвратит не объект. А строку.

Хотя нет. Все-же возможен вариант и без финализатора. :) Нужно будет применить этот подход. Ушел думать.

Добавлено через 2 минут, 39 секунд:

Djadka, подскажите, где еще можно реализовать данный подход.
Djadka
Я в ядре сделал, в классе Db, Eleanor::$Db->Query('',array(),0/*Флаг для возврата тела, для того что бы остальные компоненты были не тронутыми*/)->Fetch_assoc. Это дело в некоторых моментах компактнее, вот только вопрос, как на счёт оптимальности скорость и ресурсоёмкость??? Мне сказали что в данном случае если метод возвращает класс, то создаётся временный свой класс, но опять же в скорости в теории есть прирост. Я знаю один фраемворк он весит 70 метров и работает он только на текучки, летает он быстрее молнии, вот только в этом ли фишка.
Alexander, согласен, пример крайне неудачный.
Пока не представляю как реализовать без финализатора :(

Я бы написал что-то типа такого:

class Tpl
{
    private
        $html=[];

    public function Head($title)
    {
        $this->html[] = '<head><title>'.$title.'</title></head>';
        return $this;
    }

    public function Body($content)
    {
        $this->html[] = '<body>'.$content.'</body>';
        return $this;
    }

    public function Final()
    {
        return join("\n",$this->html);
    }

}

Пример обращения:

echo (new Tpl)->Head('Заголовок')->Body('Сгенерированный контент')->Final();


Если есть идеи как избавится от финализатора и/или массива $html, то пожалуйста изложите идею

Цитата (Alexander @ 2012-04-11, 5:12)
подскажите, где еще можно реализовать данный подход.

Ну, например, как вариант абстрагирования SQL-запросов. Где-то видел ваш пост, где вы писали о том, что не могли придумать красивую обёртку для SELECT'а
Ну так вот:

Допустим есть такой запрос:

Eleanor::$Db->Query('SELECT `id`,`sections`,`title_l`,`path`,`multiservice`,`file`,`files`,`user_groups` FROM `'.P.'modules` WHERE `id`='.(int)$Eleanor->modules['ids'][$m].' AND `active`=1 LIMIT 1');


А в случае Fluent Interface:

Eleanor::$Db->Select('id, sections, title_l, path, multiservice, file, files, user_groups')
            ->From(P.'modules')
            ->Where('`id`='.(int)$Eleanor->modules['ids'][$m])
            ->And(`active`=1)
            ->Limit(1);

Естественно всё это парсится, подставляются апострофы и т.п., но принцип, думаю, понятен.

В Zend Framework'е на днях копался, там примерно так и реализуется
(В версии 1.11: \ZendFramework-1.11.11\library\Zend\Db\Select.php)

P.S.
Тут пришло озарение :) В варианте без использования финализатора подразумевается шаманство с __toString() ?
Alexander
Цитата (Djadka @ 2020-11-28 15:46)
Я в ядре сделал, в классе Db, Eleanor::$Db->Query('',array(),0/*Флаг для возврата тела, для того что бы остальные компоненты были не тронутыми*/)->Fetch_assoc.

Зачем? Там уже и так все было реализовано. Query возвращает объект Result, который без дополнительных плясок имеет метод fetch_assoc() и fetch_row();

Цитата (wizard993 @ 2020-11-28 15:46)
Ну, например, как вариант абстрагирования SQL-запросов.

Мой опыт говорит о том, что абстрагировать SELECT запросы чаще всего невозможно. Хотя этим занимаются даже разработчики IPB. Но результат блевотный. Абстрагировать можно лишь простейшие запросы, но в этом случае смысл абстрагирования для меня теряется. Попробуйте абстрагировать запрос со сложной выборкой, статическими данными в результатах, вложенном запрос (не JOIN). Интересно, как это получится? Я даже с трудом понимаю, как можно абстрагировать UPDATE запросы, когда изменяется не одна таблица, а несколько... Даже если вам и удастся абстрагировать такие запросы, я почти уверен, что к вашему подходу придется написать не одну страницу документации. Что затрудняет понимание и отбивает желание новичков. Плюс из абстракции не всегда понятно, что хотел ею добиться автор.

Цитата (wizard993 @ 2020-11-28 15:46)
Тут пришло озарение В варианте без использования финализатора подразумевается шаманство с __toString() ?

Именно. Но там еще есть пару пикантных моментов. Напишите мне на мыло - если удастся реализовать все, как я хочу - скину вам тест версию системы с реализованным Fluent interface.
Djadka
Вот было бы интересно сравнить скорость и ресурсоёмкость с текучкой.
Цитата (Alexander @ 2012-04-11, 16:44)
Мой опыт говорит о том, что абстрагировать SELECT запросы чаще всего невозможно. Хотя этим занимаются даже разработчики IPB. Но результат блевотный. Абстрагировать можно лишь простейшие запросы, но в этом случае смысл абстрагирования для меня теряется. Попробуйте абстрагировать запрос со сложной выборкой, статическими данными в результатах, вложенном запрос (не JOIN). Интересно, как это получится? Я даже с трудом понимаю, как можно абстрагировать UPDATE запросы, когда изменяется не одна таблица, а несколько... Даже если вам и удастся абстрагировать такие запросы, я почти уверен, что к вашему подходу придется написать не одну страницу документации. Что затрудняет понимание и отбивает желание новичков. Плюс из абстракции не всегда понятно, что хотел ею добиться автор.


Который раз уже говорю спасибо за разъяснения. :)

Цитата (Alexander @ 2012-04-11, 16:44)
Именно. Но там еще есть пару пикантных моментов. Напишите мне на мыло - если удастся реализовать все, как я хочу - скину вам тест версию системы с реализованным Fluent interface.

С радостью посмотрю. Напишу в пятницу. У вас, наверное, пока и так забот хватает. А пятница уже как бы разгрузочный день.

Цитата (Djadka @ 2012-04-11, 18:48)
Вот было бы интересно сравнить скорость и ресурсоёмкость с текучкой.

Djadka, постараюсь покапать интернет на недельке, если что интересное найду - отпишусь постом.
Alexander
wizard993, все реализовал механизм по своей задумке. Стало жрать чуть меньше памяти. Кода стало так же меньше. Посмотрите потом :)
Alexander, написал на мыло :)
Djadka
А как на счёт скорость работы? Стало шустрее или нет?
Alexander
Djadka, миллисекунды не сравниваю. По-моему так же.

Добавлено через 0 минут, 19 секунд:

Могу дать архив - сами сравните. До и после.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.