Zgłoszono zapotrzebowanie na taki temat więc tworzę
Myśl przewodnia: "W jaki sposób tworzyć routery na potrzeby naszych aplikacji, jakie są wydajne a jakie nie. Jakich używać a jakich nie używać."
Przeglądając framework Zenda, system Rutowania oparty jest o jeden Router_Rewrite zawierający tablicę obiektów tras, na których poźniej wykonywana jest pętla foreach i każdemu z osobna jest wywoływana metoda $route->match($pathInfo).
Pomysł bardzo wygodny, bo możemy definiować sobie tyle tras różnego rodzaju ile chcemy, implementując oczywiście odpowiedni interfejs. Minusem jest jednak wydajność takiego rozwiązania.
Myśle że lepszym pomysłem byłoby rozdzielić Router_Rewrite na routery:
a) Rewrite (domyślny ostatni w kolejności do sprawdzania router)
- brak magazynowania tras, bo nie byłoby takiej potrzeby ponieważ router wyciąga parametry z tego co dostaje (/onas/kontakt)
B) Static (statyczny router):
- magazynuje tylko statyczne trasy i jej parametry
- brak dynamicznych parametrów
- przechowuje trasy w tablicy a indeksem tablicy jest szablon trasy (np. o-nas,kontakt.html)
- błyskawiczne znajdowanie trasy
c) Static Rewrite (statyczno-dynamiczny router):
- magazynuje tylko statyczne trasy i jej parametry
- możliwość dynamicznych parametrów (id/3)
- przechowuje trasy w tablicy a indeksem tablicy jest szablon(np. /pl/wydarzenia-o-biznesie) trasy (np. /pl/wydarzenia-o-biznesie/id/5 gdzie /pl/wydarzenia-o-biznesie to trasa statyczna a id/5 to dodatkowy parametr dynamiczny)
- dość szybkie znajdowanie tras
d) Regex (rutowanie za pomocą wyrażeń regularnych)
- magazynuje wszelkiego rodzaju trasy i ich parametry
- przechowuje trasy w tablicy a indeksem jest pattern wyrażenia regularnego
- niestety mało wydajne wyszukiwanie - konieczność użycia wyrażeń regularnych
W pierwszej kolejności nasz framework zacząłby od sprawdzania tras statycznych, następnie od statyczno - dynamicznych, potem wyrażenia regularne i na koniec rewrite który wyciąga z urla parametry jeśli nie znaleziono nic w powyższych routerach.
Po testach szybkości:
3 krotnie szybciej routing się wykonuje jeśli mamy 3 routery a trasy i parametry przechowywujemy na tablicach, niż używając jednego routera i przechowywując instancje obiektów tras w jednej tablicy.
Routing oparty o instancje obiektów tras:
Dodanie tras statycznych:0.00089502334594727
Dodanie tras regex:0.0009760856628418
Szukanie tras:0.00070309638977051
Czas całkowity:0.0026209354400635
Routing oparty o 3 routery i tablicę do przechowywania tras i parametrów:
Dodanie tras statycznych:0.00034093856811523
Dodanie tras regex:0.00036096572875977
Szukanie tras:0.00030183792114258
Czas całkowity:0.0010831356048584
Mam prośbę: czy mógłbyś wykonać miarodajne testy np. w pętli? Bo obecne mogą być wynikiem działania winampa, albo chwilowego wzrostu obciążenie procka, czy zatkania się danych na FSB ;]
Pozdrawiam.
To były testy w pętli for i <= 100, robiłem testy dla 1000 i dla 1 000 000, dla 1 000 000 tablice ukończyły test w 16 sekund, a instancje obiektow w tablicy nie ukonczyly testu z powodu braku pamięci.
Ja swój router oparłem o dynamiczne dobieranie typów. Pierwsze 2 parametry adresu tj. /klasa/metoda to nic innego jak odwolania do konkretnego controllera i jego metody. Pozostałe dane z adresu dobiera juz sobie indywidualnie controller podajac tablice typow np.
@SHiP
Wiesz, można mieć tak że jest obiekt który tłumaczy dane wejściowe (czy to z URL, konsola czy jakkolwiek) i dopiero potem przekazuję te informacje obiektowi który uruchamia odpowiednią akcję. Takie rozdzielenie pozwala zmieniać, skąd dane pochodzą, niezależnie od tego jak są wykorzystywane przy uruchamianiu odpowiednich akcji.
Bardzo dobry routing posiada Agavi, http://agavi.org/docs/tutorial/topics/basics-routing.html i http://www.agavi.org/docs/latest/manuals/manual/ch03s06.html#id930531.
W Kohanie integrują Routing oparty na tym: http://dev.horde.org/routes/
Całkiem rozbudowany system routingu.
@bigZbig
Nie chodzi o to aby wykorzystywać wiele różnych linków w aplikacji, ale aby router umożliwiał użycie takich jakie mamy ochotę i zmianę, jeśli jest taka potrzeba.
Po zmianie stare linki też powinny funkcjonować, więc nie powinno się ich po prostu pozbywać.
Nie wiem ale czasami takiego sposobu rozwiązywania routerów nie pojmuje. Może jest to pro ale jak dla mnie czasami mało elastyczne. Nie chce się spierać czy robię lepiej czy nie, po prostu przedstawię to co ja kiedyś zrobiłem i używam do dziś.
Każdy URL jaki przychodzi do aplikacji leci przez 'index.php', nie wliczając URL'i które są fizycznie istniejącymi plikami lub katalogami. układ URL'a to '/nazwaKlasyAkcji/dowolna/ilosc/parametrow'.
Każda klasa akcji ma swój własny (ja sobie to tak nazywam) miniRouter który na podstawie dowolnych parametrów wywołuje określoną metodę, która wykonuje resztę działań.
Wady to to ze miniRouter należało by definiować dla każdej klasy. Zalety to możliwość tworzenia miniRouterów dla kazdej z klasy i nie działanie na sztywnych schematach co czasami nie jest wygodne.
Pewnie to kiedyś sie rozwinie i może dojdą jakieś gotowe schematy ale na chwile obecna działa i to mnie cieszy
W temacie ostatnio nikt nie pisze, więc opiszę w jaki sposób ja robie router U mnie wszystko opiera się na wyrażeniach regularnych, jeśli jest to domena główna to pobiera tablicę z pliku:
<?php $router = http://www.php.net/array( 'wyrazenie' => http://www.php.net/array(kontroler,metoda,[opcjonalna tablica ze stalymi elementami]), ); ?>
<?php http://www.php.net/array('isdelete'=>true), ?>
No i może ja swój router opiszę. Zasada jego działania opiera się na zwykłym http://pl.php.net/explode. Czyli:
To może ja zapodam już gotowy Router. Pewnie jest do zrobienia parę zmian/dodatków ale swoją podstawową funkcję spełnia.
http://hernas.pl/download/entry-b9e3dca913dcf02b1965f0719b6ae3a2.htm
Pewnie niektórzy mają sprawniejsze pomysły, ale na razie udało mi się napisać coś takiego.
@bim2 Widze, że coś podobnego do rootera w Zend Frameworku wykombinowałeś. Ja próbuję zrobić rooter który działa na podobnej zasadzie co Twój tylko, żeby nie trzeba było nazw zmiennych w url-u podawać. Poszczególne zmienne są rozpoznawane na podstawie ich położenia w ścieżce.
W sumie można dopisać do tych confingu które położenie jak nazywa się zmienna Albo w skrypcie podawać po kolejnosci zmiennej, tylko to tyle roboty co dodanie kolejnych sposobów routingu
Najpraktyczniejszym rozwiązaniem jest już powyżej wspominane "sprawdzanie etapowe":
- strony statyczne (/rejestracja.html na moduł register, akcje home)
- wyrażenie regularne (/([a-z]).html na page, akcje view z parametrem $1)
- wszystkie pozostałe na moduł home, 404 itd
Wszystko pięknie działa, a możliwości konfiguracji praktycznie nieograniczone
Pozwolę sobie odkopać temat.
Jak proponujecie przekazywać parametry z url do metody akcji?
Jako tablicę np. $c->akcja($params); Czy może $c->akcja($id,$page); ?
I zależnie od wybranego sposobu jak proponujecie rozwiązać problem error 404?
Bo jeżeli mam url: /c/akcja/id/page to jest ok. Natomiast jeżeli ktoś dopisze /c/akcja/id/page/costam/costam2/ to w jaki sposób rozpoznać że strona nie istnieje? Bo można by w każdej metodzie-akcji zdefiniować ile powinna mieć parametrów i liczyć ile jest parametrów wejściowych... No ale to trzeba by było to samo w każdej akcji klepać.
Acha... mówię o przypadku routingu niestatycznego kiedy nie mamy w tablicy zapisanych tras. Bo jak ma się trasy to wystarczy sprawdzić czy któraś pasuje i jak żadna nie pasuje to 404.
1. W mojej opinii dane z routingu powinno sie wykorzystywac jaka dane z GET i tam je wrzucic - ew ubrac w obiekt.
2. Tak czy tak w jakis sposob musisz zapisac liczbe potrzebnych parametrow do akcji, ew parsowac w .htaccess i ustawic customowy 404.
A teraz coś innego , hasło Router, ale nie chodzi o URLe.
Mam aplikację. Dużą aplikację , która pobiera z wielu serwerów wiele plików. Zastanawiam się, jak sensownie rozdzielić obciążenie, tak, aby dać maksymalną elastyczność ( środowisko pracy jest bardzo niestabilne, dajmy na to chociazby że tylko niektóre dedykowane moga pobierac z okreslonych serwerów ) a jednocześnie w miare robic to normalnie. No to pomyslalem o ,,Routerze", choc chyba odpowiednia nazwa bardziej bylby Load Balancer, ktory pod kazdy serwis mialby tablice IP serwerów pod ktore sie laczy zasadą Round-Robin.
Dobry pomysl? Zly pomysl? Argumentujcie, propozycje mile widziane ;D
private function view($articleName, $articleCategory, $articleID) { ... }
if(http://www.php.net/func_num_args() > X) // strona nie istnieje
ja u siebie mam rozwiązane to w ten sposób że do klasy kontrolera przekazywany jest obiekt z parametrami
i potem w kontrolerze już tylko
public function indexPage() { http://www.php.net/echo $this->router->args[0] ; }
/article/:category/:id/:slug public function viewAction($id); public function viewAction($id, $category); public function viewAction($category, $id); public function viewAction($category, $id, $slug); // Wszysystkie powyższe są poprawne
Będę musiał sprawdzić jak to jest dokładnie zrobione, bo wygląda co najmniej interesująco
Tak na szybkiego spojrzałem i widzę że wymaga to także definiowania kolejnego pliku z regułami routera więc jednak trzeba niestety więc kodu nastukać Ale rozwiązanie jest interesujące
Mój router
http://wklej.to/UbZca
Klucz zabezp. - 123
Dobrze to zrobiłem? Jeszcze nie skończone, bo brakuje wymagań dla zmiennych tj. tylko liczby, tekst, bez myslnikow itd. itd.
Glownie prosze o analize metody route, bo calkiem rozbudowana mi sie wydaje, moze namieszalem? Może okaże się, że dodam kilka ścieżek i samo przeprasowanie tego przez router zajmie 70% czasu wykonywania sie skryptu?
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)