Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ Archiwum Pro _ Filtry i kolejność wykonywania

Napisany przez: sf 7.03.2007, 13:29:42

Posiadam klasę HFilters:

  1. <?php
  2. class HFilters
  3. {
  4. private $aFilterList = http://www.php.net/array();
  5.  
  6.  
  7. private $oContext;
  8.  
  9.  
  10. public function __construct(& $oContext)
  11. {
  12. $this->oContext = & $oContext;
  13. }
  14.  
  15.  
  16. public function add(iFilter $oFilter, $iPreWeight = 10, $iPostWeight = 10)
  17. {
  18. $this->aFilterList[] = $oFilter;
  19. }
  20.  
  21.  
  22. public function pre()
  23. {
  24. foreach($this->aFilterList as $oFilter) {
  25. $oFilter->pre($this->oContext);
  26. }
  27. }
  28.  
  29.  
  30. public function post()
  31. {
  32. foreach($this->aFilterList as $oFilter) {
  33. $oFilter->post($this->oContext);
  34. }
  35. }
  36. }
  37. ?>


IFilter wygląda następująco:
  1. <?php
  2. interface iFilter
  3. {
  4. public function pre($oContext);
  5.  
  6.  
  7. public function post($oContext);
  8. }
  9. ?>


Mam problem z zaimplementowaniem kolejności wykonywania metod pre() i post() w HFilter wg ustalonwej wagi podanej w metodzie add(). Czy ktoś ma jakiś pomysł?

Napisany przez: mike_mech 7.03.2007, 13:50:41

Proste.
Zamiast HFilters::aFilterList daj HFilters::aPreFilterList i HFilters::aPostFilterList. Potem przy wrzucaniu daj:

  1. <?php
  2. // ...
  3.  
  4. public function add(iFilter $oFilter, $iPreWeight = 10, $iPostWeight = 10)
  5. {
  6. $this->aPreFilterList[$iPreWeight] = $oFilter;
  7. $this->aPostFilterList[$iPostWeight] = $oFilter;
  8.  
  9. // Tutaj posortuj tak jak Ci wygodnie
  10. }
  11.  
  12. // ...
  13. ?>

A na końcu wykonaj filtry, uwzględniając powyższe zmiany.

P.S.
Zamiast pętli po tablicach nie lepiej użyć iteratorów?

P.S.2
Po co Ci & w konstruktorze?

update (po przemyśleniu)
Tak w ogóle to moim zdaniem źle się za to zabrałeś.
Skoro (na to przynajmniej) metody pre() i post() są widocznie rozłączne to czemu nie dasz:
  1. <?php
  2.  
  3. abstract class AbstractFilter implements Filter
  4. class PreFilter extends AbstractFilter
  5. class PostFilter extends AbstractFilter
  6. class FilterChain implements Filter
  7.  
  8. ?>

Miałbyś wtedy łańcuchy filtrów. Każdy taki łańcuch wywołałby wszystkie swoje filtry niezależnie i w dowolnej kolejności. Byłoby troszkę ładniej i przejrzyściej zorganizowane.

Napisany przez: sf 7.03.2007, 13:51:43

Nie sprawdzi się jeśli ustawimy dla dwóch filtrów taką samą wagę, jeden nadpisze drugi.

Cytat(mike_mech @ 7.03.2007, 13:43:37 ) *
P.S.
Zamiast pętli po tablicach nie lepiej użyć iteratorów?

W tym przypadku nie robi to raczej różnicy.. bo implemetnacja i tak nie wychodzi nigdzie na zewnątrz. Chyba, że itereatory są szybsze.

Cytat(mike_mech @ 7.03.2007, 13:43:37 ) *
P.S.2
Po co Ci & w konstruktorze?

Mój głupi błąd.

Dopisek:
To musi być jedna klasa ponieważ np. załóżmy, że mamy filtr benchmark.. nie chce tworzyć benchmarkStart i benchmarkEnd. Wole to umieścić w jednej klasie.

Napisany przez: mike_mech 7.03.2007, 13:55:07

Cytat(sf @ 7.03.2007, 13:51:43 ) *
Nie sprawdzi się jeśli ustawimy dla dwóch filtrów taką samą wagę, jeden nadpisze drugi.
To u góry to był tylko zarys pomysłu.
Już Twoja w tym działka jak stworzyć te tablice żeby się nie nadpisały. Przecież nie jest to nic strasznie trudnego tongue.gif

Napisany przez: sf 7.03.2007, 15:52:49

Implementacja wcale nie jest taka prosta. Ponieważ klucz musi być unikalny, czyli można by to rozwiązać poprzez dodanie iteracyjnego przyrostku, ale to powoduje, że musimy ustalić zakres. Jeśli to będzie liczba złożona z jednej cyfry to mamy ograniczenie do 10 pozycji tylko.

Przy okazji Twój przykład kopiuje dwukrotnie ten sam obiekt. Rozwiązałem całość w następujący sposób.

  1. <?php
  2. class HFilters
  3. {
  4. /** Filters objects list. */
  5. private $aFilters = http://www.php.net/array();
  6.  
  7.  
  8. /** Pre methods order. */
  9. private $aPreOrder = http://www.php.net/array();
  10.  
  11.  
  12. /** Post methods order. */
  13. private $aPostOrder = http://www.php.net/array();
  14.  
  15.  
  16. /** Context objects. */
  17. private $oContext;
  18.  
  19.  
  20. public function __construct($oContext)
  21. {
  22. $this->oContext = & $oContext;
  23. }
  24.  
  25.  
  26. public function add(iFilter $oFilter, $iPreWeight = 10, $iPostWeight = 10)
  27. {
  28. $this->aFilters[] = $oFilter;
  29. $this->aPreOrder[] = $iPreWeight;
  30. $this->aPostOrder[] = $iPostWeight;
  31. }
  32.  
  33.  
  34. public function pre()
  35. {
  36. http://www.php.net/asort($this->aPreOrder);
  37. foreach($this->aPreOrder as $iKey => $iWeight) {
  38. $this->aFilters[$iKey]->pre($this->oContext);
  39. }
  40. }
  41.  
  42.  
  43. public function post()
  44. {
  45. http://www.php.net/asort($this->aPostOrder);
  46. foreach($this->aPostOrder as $iKey => $iWeight) {
  47. $this->aFilters[$iKey]->post($this->oContext);
  48. }
  49. }
  50. }
  51.  
  52. ?>

Napisany przez: mike_mech 7.03.2007, 19:20:47

Cytat(sf @ 7.03.2007, 15:52:49 ) *
Implementacja wcale nie jest taka prosta. Ponieważ klucz musi być unikalny, czyli można by to rozwiązać poprzez dodanie iteracyjnego przyrostku, ale to powoduje, że musimy ustalić zakres. Jeśli to będzie liczba złożona z jednej cyfry to mamy ograniczenie do 10 pozycji tylko.
Niekoniecznie.
Jeśli taki indeks jest już zajęty to można z niego zrobić tablicę smile.gif i zagnieździć się głębiej.
Ogólnie.
1. Sprawdzam czy podana waga istnieje.
2. Jeśli nie to dodaję do tablicy.
3. Jeśli tak to sprawdzam czy pod indeksem jest tablica. Jeśli tak to dopisuję się do niej (z kolejnym indeksem)
4. Jeśli indeks istnieje i nie jest tablicą. To wyjmuję obiekt znajdujący się pod tym indeksem a wkładam tablicę gdzie ten obiekt jest jedynym elementem.

To bardzo prosty algorytm.

Cytat(sf @ 7.03.2007, 15:52:49 ) *
Przy okazji Twój przykład kopiuje dwukrotnie ten sam obiekt.
Nieprawda.
Przeanalizuj poniższy przykład:
  1. <?php
  2.  
  3. class testClass {
  4. public $property = 10;
  5. }
  6.  
  7. $testObject = new testClass();
  8.  
  9. $array1 = http://www.php.net/array();
  10. $array1[] = $testObject;
  11. $array2 = http://www.php.net/array();
  12. $array2[] = $testObject;
  13.  
  14. $array1[0]->property = 20;
  15.  
  16. http://www.php.net/echo $array2[0]->property;
  17.  
  18. ?>
(PHP5 naprawdę już nie jest takie ułomne jeśli chodzi o obiekty smile.gif )

Napisany przez: Strzałek 8.03.2007, 12:22:45

Rozwiązanie takich filtrów jak dla mnie jest trochę mało wygodne. Ja rozwiązuję to o wiele wygodniej i filtry mają większe możliwości. Mianowicie filtr implemetuje interface z jedną metodą - execute która przyjmuje jako argument $filterChain'a z publiczną metodą next() która wykonuje następny filtr. Kod zapisany przed wykonaniem metody next to pre, a po metodzie to post. Proste w działaniu, banalne w implementacji.

  1. <?php
  2.  
  3. interface IFilter {
  4.  public function execute(IFilterChain $filterChain);
  5. }
  6.  
  7. interface IFilterChain {
  8.  public function addFilter(IFilter $filter);
  9.  public function http://www.php.net/next();
  10. }
  11.  
  12.  class FilterChain implements IFilterChain {
  13.  
  14.  public $filters = http://www.php.net/array();
  15.  
  16.  
  17. public function addFilter(IFilter $filter){
  18. $this -> filters[] = $filter;
  19. }
  20.  
  21. public function http://www.php.net/next(){
  22. if($filter = http://www.php.net/array_shift($this -> filters)){
  23.  $filter -> execute($this);
  24.  }
  25. }
  26.  
  27. public function execute(){
  28.  $this -> http://www.php.net/next();
  29. }
  30.  
  31.  }
  32.  
  33.  
  34.  class AuthFilter implements IFilter {
  35.  
  36. public function execute(IFilterChain $filterChain){
  37.  
  38. if($auth -> isLoged()){
  39.  $this -> http://www.php.net/next();
  40. }else{
  41. http://www.php.net/echo 'zaloguj się';
  42. }
  43.  
  44. }
  45.  
  46.  }
  47.  
  48.  class ExecutionFilter implements IFilter {
  49.  
  50.  public function execute(IFilterChain $filterChain){
  51.  
  52.  
  53. //odpalamy aplikacje
  54.  $filterChain -> http://www.php.net/next();
  55.  }
  56.  
  57.  }
  58.  
  59.  
  60. $filterChain = new FilterChain();
  61.  
  62. $filterChain -> addFilter(new AuthFilter());
  63. $filterChain -> addFilter(new ExecutionFilter());
  64.  
  65. $filterChain -> execute();
  66.  
  67. ?>


Ufff, pisane z palca na lekcji historii (mamy w sali od inf.) Rkingsmiley.png

Mam nadzieję że nie ma błędów i ogólny koncept zrozumiany.
Pozdrawiam aarambo.gif

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)