Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Filtry i kolejność wykonywania
sf
post 7.03.2007, 13:29:42
Post #1





Grupa: Zarejestrowani
Postów: 1 597
Pomógł: 30
Dołączył: 19.02.2003
Skąd: Tychy

Ostrzeżenie: (0%)
-----


Posiadam klasę HFilters:
  1. <?php
  2. class HFilters
  3. {
  4. private $aFilterList = 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ł?

Ten post edytował sf 7.03.2007, 13:30:49


--------------------
Zapraszam na mój php blog, tworzenie stron.
Go to the top of the page
+Quote Post
mike
post 7.03.2007, 13:50:41
Post #2





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
sf
post 7.03.2007, 13:51:43
Post #3





Grupa: Zarejestrowani
Postów: 1 597
Pomógł: 30
Dołączył: 19.02.2003
Skąd: Tychy

Ostrzeżenie: (0%)
-----


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.

Ten post edytował sf 7.03.2007, 13:53:37


--------------------
Zapraszam na mój php blog, tworzenie stron.
Go to the top of the page
+Quote Post
mike
post 7.03.2007, 13:55:07
Post #4





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


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

Ten post edytował mike_mech 7.03.2007, 13:55:53
Go to the top of the page
+Quote Post
sf
post 7.03.2007, 15:52:49
Post #5





Grupa: Zarejestrowani
Postów: 1 597
Pomógł: 30
Dołączył: 19.02.2003
Skąd: Tychy

Ostrzeżenie: (0%)
-----


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 = array();
  6.  
  7.  
  8. /** Pre methods order. */
  9. private $aPreOrder = array();
  10.  
  11.  
  12. /** Post methods order. */
  13. private $aPostOrder = 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. 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. asort($this->aPostOrder);
  46. foreach($this->aPostOrder as $iKey => $iWeight) {
  47. $this->aFilters[$iKey]->post($this->oContext);
  48. }
  49. }
  50. }
  51.  
  52. ?>


Ten post edytował sf 7.03.2007, 15:54:22


--------------------
Zapraszam na mój php blog, tworzenie stron.
Go to the top of the page
+Quote Post
mike
post 7.03.2007, 19:20:47
Post #6





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


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 = array();
  10. $array1[] = $testObject;
  11. $array2 = array();
  12. $array2[] = $testObject;
  13.  
  14. $array1[0]->property = 20;
  15.  
  16. echo $array2[0]->property;
  17.  
  18. ?>
(PHP5 naprawdę już nie jest takie ułomne jeśli chodzi o obiekty smile.gif )
Go to the top of the page
+Quote Post
Strzałek
post 8.03.2007, 12:22:45
Post #7





Grupa: Przyjaciele php.pl
Postów: 384
Pomógł: 6
Dołączył: 11.09.2004
Skąd: Grodzisk Mazowiecki

Ostrzeżenie: (0%)
-----


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 next();
  10. }
  11.  
  12.  class FilterChain implements IFilterChain {
  13.  
  14.  public $filters = array();
  15.  
  16.  
  17. public function addFilter(IFilter $filter){
  18. $this -> filters[] = $filter;
  19. }
  20.  
  21. public function next(){
  22. if($filter = array_shift($this -> filters)){
  23.  $filter -> execute($this);
  24.  }
  25. }
  26.  
  27. public function execute(){
  28.  $this -> 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 -> next();
  40. }else{
  41. 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 -> 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


--------------------
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 29.03.2024 - 11:31