Форумы портала PHP.SU » Разное » Обсуждение статей » Текучий интерфейс

Страниц (1): [1]
 

1. sKaa - 16 Ноября, 2011 - 00:12:43 - перейти к сообщению
Я сразу оговорюсь, что эта статья для тех кто уже хоть чуть-чуть начал или начинает понимать принципы ООП. Я сам ещё можно сказать "New bie" в этом деле.
Итак думаю критики которые сейчас читают эту статью знакомы с понятием "Текучий интерфейс". Примеры можно встретить во многих фрейворках например Zend. Что-же это такое, рассмотрим пример класса Template :
PHP:
скопировать код в буфер обмена
  1.  
  2. class Template {
  3.         public $vars = array();
  4.         public $content;
  5.         public $parse_tpl;
  6.        
  7.         public function set($name, $val = "") {
  8.                 if(!is_array($val)) {
  9.                         $this->vars['{' . $name . '}'] = $val;
  10.                 } elseif(is_array($val)) {
  11.                         foreach($val as $k => $v) {
  12.                                 $this->vars['{' . $name . '}'] .= $v;
  13.                         }
  14.                 } else {
  15.                         $this->vars[$name] = "";
  16.                 }
  17.         }
  18.        
  19.         public function parse($tpl) {
  20.                 $this->parse_tpl = file_get_contents($tpl);
  21.                 foreach($this->vars as $k => $v) {
  22.                         $this->parse_tpl = str_replace($k, $v, $this->parse_tpl);
  23.                 }
  24.                 return $this->parse_tpl;
  25.         }
  26.        
  27.         public function tpl($tpl) {
  28.                 $this->content = file_get_contents($tpl);
  29.         }
  30.        
  31.         public function out_content() {
  32.                 foreach($this->vars as $key => $val) {
  33.                         $this->content = str_replace($key, $val, $this->content);
  34.                 }
  35.                 echo $this->content;
  36.         }
  37.  
  38. }
  39.  


Использовать этот класс достаточно просто, примерно такой описан тут на сайте в одном из уроков : http://php.su/articles/?cat=exam...les&page=006
PHP:
скопировать код в буфер обмена
  1.  
  2. // Создаем экземпляр класса
  3. $tpl = new Template();
  4. $tpl->tpl('template/index.tpl'); // Загружаем содержимое файла в переменную $content внутри класса
  5. $header = $tpl->parse('template/header.php'); // Загружаем содержимое файла в отдельную переменную $header, если разобрать метод класса parse видно, что в конце концов он возвращает строку ( return $this->parse_tpl; )
  6.  
  7. $body =  $tpl->parse('template/header.php'); // Аналогично с предыдущей переменной $header
  8. $tpl->set('header', $header); // Метод заменяет в загруженном шаблоне index.tpl все повторы строки {header} на содержимое файла $header
  9. $tpl->set('body', $body); // Аналогично с предыдущем.
  10. $tpl->out_content();  // Выводим содержимое
  11.  

Итак это был обычный пример. А что если немного изменить наши методы класса, пусть они возвращают нам сам класс как объект после завершения :
PHP:
скопировать код в буфер обмена
  1.  
  2. class Template {
  3.         public $vars = array();
  4.         public $content;
  5.         public $parse_tpl;
  6.        
  7.         public function set($name, $val = "") {
  8.                 if(!is_array($val)) {
  9.                         $this->vars['{' . $name . '}'] = $val;
  10.                 } elseif(is_array($val)) {
  11.                         foreach($val as $k => $v) {
  12.                                 $this->vars['{' . $name . '}'] .= $v;
  13.                         }
  14.                 } else {
  15.                         $this->vars[$name] = "";
  16.                 }
  17.         return $this;
  18.         }
  19.        
  20.         public function parse($tpl) {
  21.                 $this->parse_tpl = file_get_contents($tpl);
  22.                 foreach($this->vars as $k => $v) {
  23.                         $this->parse_tpl = str_replace($k, $v, $this->parse_tpl);
  24.                 }
  25.                 return $this->parse_tpl;
  26.         }
  27.        
  28.         public function tpl($tpl) {
  29.                 $this->content = file_get_contents($tpl);
  30.                 return $this;
  31.         }
  32.        
  33.         public function out_content() {
  34.                 foreach($this->vars as $key => $val) {
  35.                         $this->content = str_replace($key, $val, $this->content);
  36.                 }
  37.                 echo $this->content;
  38.         }
  39.  
  40. }
  41.  

Как видно в методах tpl, set появилась новая строка return $this;
Какие преимущества нам это дает? Более удобный синтаксис :
PHP:
скопировать код в буфер обмена
  1.  
  2. $tpl = new Template(); // Экземпляр класса
  3. $tpl ->tpl('template/index.tpl')  // Загружаем шаблон
  4.       ->set('header', $tpl->parse('template/header.tpl')) // Парсим все {header} на содержимое файла header.tpl
  5.       ->set('body', $tpl->parse('template/body.tpl'))
  6.       ->out_content(); // Выводим контент..
  7.  

Сильно не критикуйте, это моя первая статья) Я ужасно нервничал и мог что-то упустить. Если я где-то тут произвел "подмену терминов" напишите всё поправлю.
2. caballero - 16 Ноября, 2011 - 00:59:41 - перейти к сообщению
Цитата:
Итак думаю критики которые сейчас читают эту статью знакомы с понятием "Текучий интерфейс".

Где вы такое "понятие" вычитали.

Цитата:
Какие преимущества нам это дает? Более удобный синтаксис :


Очень спорный вопрос. Конечно "цепочечные" вызовы выглядят компактнее но очен неудобны для чтения. Потому как непонятно где какой объект вызывается. Ведь во время следующего вызова обект может вернуть не $this а другой объект который тоже пойдет вызывать цепочку. И пойми где какой метод какого объекта и что он возвращает.
Кроме того чисто стилистически. Если функция по бизнес-логике ничего возвращать не должна - нефиг там писать return со всякой, не относящейся к логике рабты программы, херней.
В данном случае. С какого перепугу метод set который, судя по названию что то устанавливает, еще что то и возвращает? Максимум что он мог бы возвращать если по уму, это результат присвоения true/false (удвчно неудачно.)
3. sKaa - 16 Ноября, 2011 - 01:17:05 - перейти к сообщению
caballero пишет:
Где вы такое "понятие" вычитали.

Где - где. Известно где))
Я готов допустить что метод set не очень удачный пример. Возмножно его просто назвать чуть по другому надо было, и таких интуитивных ассоциаций у тебя не возникало бы..
PHP:
скопировать код в буфер обмена
  1.  
  2. class image {
  3.  
  4. private
  5.         $width,
  6.         $height,
  7.         $img;
  8.  
  9.         public function loadImg($img){
  10.                 /* .... */
  11.                 $this->img = $img;
  12.                 return $this;
  13.                 }
  14.  
  15.         public function imgWidth($w){
  16.                 $this->width = $w;
  17.                 return $this;
  18.         }
  19.         public function imgHeight($h){
  20.                 $this->height = $h;
  21.                 return $this;
  22.         }
  23.         public function Draw(){
  24.                 echo 'Img : ' . $this->img .
  25.                                 ' Width : ' . $this->width .
  26.                                 ' Height : ' . $this->height ;         
  27.         }
  28.        
  29. }
  30.  
  31. $image = new Image();
  32. $image->loadImg('img')->imgWidth('50')->imgHeight('100')->Draw();
  33.  
4. caballero - 16 Ноября, 2011 - 01:49:13 - перейти к сообщению
Цитата:
Где - где. Известно где))

понятно - высосано из пальца

Цитата:
Я готов допустить что метод set не очень удачный пример


Неважно какой метод. Важен сам принцип - нефиг методу что то возвращать если ему по логике программы нечего возвращать. Тем более глупо переимновывать метод - вместо понятного имени писать что попало лишь бы вписаться в хрень под диковинным названием "текучий интерфейс".


Впрочем в некоторых экзотических фреймворках (типа onPHP) такой подход используется.
5. DeepVarvar - 16 Ноября, 2011 - 06:22:58 - перейти к сообщению
sKaa, просто caballero не пользует и пользовать не будет, судя по настрою.
Я тут тоже подумал такое же "ичо":
PHP:
скопировать код в буфер обмена
  1. $image->loadImg('img',50,100);
  2. $image->Draw();

И чо? Радость
Чем оно не удобнее или не понятнее?
(Добавление)
caballero, хотя jquery так и работает, всегда возвращая this.
CODE (javascript):
скопировать код в буфер обмена
  1. $("#elem").action1().action2().action3();

Но мне оно не было удобным никогда.
6. Мелкий - 16 Ноября, 2011 - 07:53:32 - перейти к сообщению
PHP:
скопировать код в буфер обмена
  1. foreach (model::factory('foo')->param(1)->list() as $item) {}

А теперь представьте равнозначный кусок без использования такого приёма. Сколько места займёт?

По классической концепции MVC, шаблон может и должен самостоятельно обращаться к модели за своими данными, не беспокоя контроллер по пустякам. При этом, такая запись весьма удобна и не выглядит нагромождением.
7. DeepVarvar - 16 Ноября, 2011 - 07:55:52 - перейти к сообщению
PHP:
скопировать код в буфер обмена
  1. foreach (model::factory('foo')->listParam(1) as $item) {}
Не?
8. Мелкий - 16 Ноября, 2011 - 07:59:09 - перейти к сообщению
DeepVarvar пишет:
factory('foo')->

А это что? Тот самый текучий интерфейс. Без него было бы:
PHP:
скопировать код в буфер обмена
  1. $model = Model::factory('foo');
  2. foreach($model->listParam(1) as $item) {}


Пусть даже так.
А если параметров не 1-2, а много? И они необязательны? Передавать массивом и в методе разбирать? Реализовывать методы вывода на все случаи жизни?
9. EuGen - 16 Ноября, 2011 - 08:05:14 - перейти к сообщению
Мне кажется, что не стоит спорить, что лучше - использовать такие вызовы и организацию методов или нет. Ведь всегда, при использовании любой технологии должно быть понимание, когда это делать нужно, а когда - нет.
Например, здесь -
sKaa пишет:
$image->loadImg('img')->imgWidth('50')->imgHeight('100')->Draw();

это вовсе не нужно, а здесь -
Мелкий пишет:
foreach (model::factory('foo')->param(1)->list() as $item) {}

очень даже.
Это я к тому, что случаи бывают разные, невозможно для вообще всех решить, что использовать. Ну и, разумеется, нужно знать меру.
10. DeepVarvar - 16 Ноября, 2011 - 08:07:37 - перейти к сообщению
EuGen пишет:
случаи бывают разные
+100500.
EuGen пишет:
нужно знать меру
+ еще столько же Закатив глазки
11. caballero - 16 Ноября, 2011 - 09:31:00 - перейти к сообщению
Цитата:
model::factory('foo')->param(1)->list()


здесь как ражз все логично
фабрика возвращает объект объект дергает некую функцию которая возвращает список

обсуждалась ситуация когда все функции котрые не возвращают бизнес данные, возвращают указатель $this
12. Мелкий - 16 Ноября, 2011 - 09:39:07 - перейти к сообщению
caballero, ну. Метод param как раз ничего, кроме this не возвращает. Хотя является классическим сеттером с точки зрения внешнего наблюдателя.
13. caballero - 16 Ноября, 2011 - 09:59:17 - перейти к сообщению
тогда параметр должен быть в функции list()
тем более параметр предназначен для нее
а если параметр не только для нее то он должен быть в конструкторе класса (фабричном методе)
14. sKaa - 16 Ноября, 2011 - 11:29:45 - перейти к сообщению
caballero пишет:
понятно - высосано из пальца

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

http://ru[dot]wikipedia[dot]org/wiki/Fluent_interface

А в остальном согласен с EuGen. Должно быть четкое понимание где стоит делать такой "текучий интерфейс" а где нет.
Пацаны расслабьтесь ) я не гуру пхп, только учусь ) Я всего лишь попробовал написать, рад, что тема у вас вызвала хоть какой-то интерес )

 

Powered by ExBB FM 1.0 RC1