Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Układ klas w core FW
Forum PHP.pl > Forum > PHP > Pro > Archiwum Pro
Athlan
Od dawna używam mojego FW do trzerzenia projektów. Moje klasy są umieszczone w katalogu /core/ frameworka, który rzy tworzeniu instancji głownej klasy jest skanowany. W taki sposób mapowane są wszystkie klasy, które później w __autoload() są includowane po wygenerowanych ścieżkach.

Ostatnio jednak pomyślałem, że jest to rozwiązanie bardzo elastyczne, jednakże pochłania te kilka milisec działania aplikacji. Pokusiłem się o zastanowienie jak inaczej można ładować klasy. Podsunął mi się projekt Zend Framework i podobna do niego aplikacja Rapide. Scieżka tak naprawde zawarta jest w nazwie klasy, przysłowiowe poziomy katalogów wyznaczają znaki _ . Poztanowiłem zebra plusy i minusy obu sposobów.

Mapowanie core:
  • [+] Klasy mogą leżeć w różnych folderach, niezależnie od ich nazwy
  • [+] Luźne powiązanie pomiędzy nazwą klasy, a ścieżką położenia pliku
  • [-] Trzeba zmapować core
Rozwiązanie Zend Framework:
  • [+] Nie trzeba mapować core, ścieżki są sztywne
  • [-] Nazwa jest ściśle uzależniona od położenia klasy
  • [-] Masa folderów z zazwyczaj jednym plikiem wyjątku
Mimo tego, że więcej minusów znalazłem w opracowaniu Zend'a i tak jestem bardziej przychylny do tego sposobu, bo nazwę przykładowo Zend_Cache_Exception, można zmienić na Zend_Exception_cache, wówczas mamy jeden folder ze wszystkimi wyjątkami. To samo tyczy się interfejsów.

Gdyzie mnie również nazewnictwo, każde wejście do folderu to znak _. Chciałbym, zby wejscie do folderu było rozdzialane poprzez kolejną wielką literę, np zamiast Zend_Cache_Exception piszemy ZendCacheException. To milsze dla (przynajmniej mojego) oka. W związku z tym napisałem skrypt (na szybko funkcja mniej więcej jak by się dzielił string, oczywiście tablicę zamienie na stringi oddzielone "/"):
  1. <?php
  2.  
  3. function ExplodeByUpper($sString)
  4. {
  5. $aExplosion = array();
  6.  
  7. $iLenght = strlen($sString);
  8. $iLastPosition = $iLenght;
  9.  
  10. for($iPosition = $iLenght - 1; $iPosition >= 0; $iPosition--)
  11. {
  12. if($sString[$iPosition] === strtoupper($sString[$iPosition]))
  13. {
  14. $aExplosion[] = substr($sString, $iPosition, ($iLastPosition - $iPosition));
  15. $iLastPosition = $iPosition;
  16. }
  17. }
  18.  
  19. return array_reverse($aExplosion);
  20. }
  21.  
  22. var_dump(ExplodeByUpper('AlaMaBrzydkiegoKota'));
  23.  
  24. ?>

Prph powiedział, że moje nazewnictwo klas (rozpoczynające dir entry z wielkich liter) może mnie ograniczyć, dlaczego to nie wiem... rozmowa się urwała, dlatego proszę o dokładne wyjaśnienie.

Co Wy na ten temat sądzicie? Jaki uklad wybrać? A może macie inne pomysły rozmieszczenia plikow komponentów framewroka?

Prosiłbym o przykłady, teorię znam. Jak Wy macie to zrobione w swoich FW smile.gif

Pozdrawiam, Athlan smile.gif
dr_bonzo
Cytat
Prph powiedział, że moje nazewnictwo klas (rozpoczynające dir entry z wielkich liter) może mnie ograniczyć,

Bo mozesz miec nazwy 'pakietow' tylko jedno wyrazowe. GUIItemFactory.php wrzuci ci do
G/U/I/Item/Factory, tak?

Cytat
[-] Trzeba zmapować core

I jaki w tym problem? Robisz to raz i zapisujesz mape. Poprzenosisz pliki -- generujesz mape od nowa.
Athlan
Cytat
I jaki w tym problem? Robisz to raz i zapisujesz mape. Poprzenosisz pliki -- generujesz mape od nowa.

U mnie mapa wczytuje generowana jest za każdym startupem frameworka. Skanowane sa wszystkie foldery i podfoldery składu frameworka. Możnaby było generować jakąś teblicę zaserializowaną z mapą plików, ale IMHO za dużo kombonowania.

Co do pakietu: Zapis będzie trochę inny wówczas smile.gif
athabus
Cytat(Athlan @ 20.01.2007, 18:00:47 ) *
Rozwiązanie Zend Framework:
  • [+] Nie trzeba mapować core, ścieżki są sztywne
  • [-] Nazwa jest ściśle uzależniona od położenia klasy
  • [-] Masa folderów z zazwyczaj jednym plikiem wyjątku


Twoje minusy to moim zdaniem plusy smile.gif Nie wiem czy coś pisałeś w ZF czy tylko znasz go z widzenia, ale moje odczucie jest takie, że organizacja plików jest super. Dzięki temu jest jakiś schemat nazewnictwa, który łatwo opanować. Ostatnio łapie się na tym, że częściej sprawdzam jak się nazywają moje klasy niż te z ZF choć bawię się tym frameworkiem relatywnie krótko. Zawsze wiem co idzie w jakiej kolejności. Osobiście nie przeszkadza mi duża liczba folderów - nawet wolę gdy w folderze jest kilka plików zamiast 20... jakoś łatwo mi się szuka.
No ale to co piszę to subiektywne odczucia - Ty możesz mieć inaczej.

Co do kwestii wydajności, to jeśli zapisujesz mapę do pliku to nie powinno być problemów - sam tak robię z moimi klasami i jest ok. Jeśli natomiast za każdym razem skanujesz swoje foldery w poszukiwaniu odpowiedniej klasy... to warto to zmienić w pierwszej kolejności.

Sposób Zenda też nie jest idealny - operacje na stringach typu explode itp są podobno dość kosztowne (nie sprawdzałem więc nie wiem na 100% - ktoś o tym pisał w temacie o autoloaderach). Ale jednak wygoda użytkowania sprawia, że zamierzam przepisać swoje klasy na taką właśnie organizację.

//edit

Cytat
U mnie mapa wczytuje generowana jest za każdym startupem frameworka. Skanowane sa wszystkie foldery i podfoldery składu frameworka. Możnaby było generować jakąś teblicę zaserializowaną z mapą plików, ale IMHO za dużo kombonowania.

Generowanie mapy za każdym razem od początku to baaardzo zły pomysł. Serializowanie tego to kilka linijek kodu, a korzyści są ogromne.
dr_bonzo
Cytat
Możnaby było generować jakąś teblicę zaserializowaną z mapą plików, ale IMHO za dużo kombonowania.

To nie narzekaj na swoj wolny skrypt.
Ilez to roboty cie czeka -- nie ma mapy to ja tworzysz (juz to masz zrobione), ta tablice ktora generujesz wrzucasz do serialize i do pliku. A gdy mapa jest to ja odczytujesz i odserializujesz. 10 min roboty.
cadavre
Ja dziś napisałem klasę do obsługi __autoload'u po lekturze ostatniej rozmowy w topiku tutaj na forum. Tworzę mapę (służy do tego metoda), która serializuje mapę klas i ją odczytuję. Dalej ewentualnie w wyjątku mogę użyć metody przeszukującej wybrany folder i jego podfoldery w poszukiwaniu klasy. Dopiero wtedy jeśli nie znajdzie - exituje.

@Athlan - z tego co widzę to dopisanie u Ciebie metody cacheującej mapę to wcale nie tak dużo pracy. Lepiej włożyć czas na tworzenie takowej niż pisać nową implementację a'la ZF.
Athlan
@cadavre, tak ale myśle nad tym, żeby się robiła od nowa na przykład co godzinę, lub gdy coś się zmieni w core. Takie a'la md5_file() dla folderu. Jeżli układ zmieni się, wówczas zrobiona zostanie mapa. Nie wiem czy jestem w dobrym toku rozumowania, bo mapa powinna się sama odświeżać, jeżeli zmienie coś w Core, bo nie za każdym razem będę pamiętał o wyczyszceniu mapy, aby sie stworzyła.

Jakieś pomysły na md5_file() na folder? smile.gif
cadavre
md5 na folder? Odczytać RecursiveDirectoryIterator'em wszystkie foldery i pliki (nazwy, bo zawartości nie potrzeba), połączyć w string i shashować? Troszkę dzikie rozwiązanie... tongue.gif

  1. <?php
  2.  
  3. $objDir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('./folder_z_klasami'),true);
  4. foreach ($objDir as $objFile) {
  5. $toHash .= $objFile;
  6. }
  7.  
  8. echo md5($toHash);
  9.  
  10. ?>

Może zbyt ogólne, bo zmiana jednej literki w nazwie pliku/folderu powoduje zmianę hasha (w sumie to tak ma być), ale foldery mogą zawierać pliki, które nie są klasami.

EDIT: Innego sposobu niż pobranie nazw folderów/plików nie ma do uzyskania miarodajnego hasha. Z tym, że to rozwiązanie na pętli x100 wykonuje się 1,03-0,98 sekundy dla zaledwie 14 folderów i 46 plików. Dość sporo.
Cysiaczek
Proponuje prościej. Zrób mapę i zapakuj do statycznego cache. Czy naprawdę cache musi być odświeżany automatycznie przy każdej zmianie zawartości katalogu z klasami? Wydaje mi się, że jest to przydatne jednie w fazie tworzenia lub aktualizacji aplikacji.
Może po prostu ustaw jakąś zmienną konfiguracyjną, która będzie za to odpowiadała? Gdy wiesz, że będziesz zmieniał pliki, to po prostu wyłączasz cache i działasz.

Cytat
1,03-0,98 sekundy


Taaa : D To nie jest dość sporo - to zaj... dużo. W tym czasie odpalisz 4 przeciętne żądania : )

Pozdrawiam.
Athlan
@cadavre, no tak, ale mapujemy core, a tego chemy uniknąć tongue.gif
Cytat
1,03-0,98 sekundy

O.O Przecież to masakrycznie dużo... u mnie mapowanie to 0.0002 sec.

Chyba nie ma innego sposobu. Cache mapy będzie czyszczony przeze mnie ręcznie, lub będzie porównywana wersja frameworka z tą, która jest zawarta w cache. Jeżeli wersja będzie się różnić, wówczas zostanie wykonana nowa mapa. Wersja frame'a jest zawarta w stałej Vframe::VERSION (wiedziałem że kiedyś się przyda biggrin.gif )

Czyli pozostawać przy mapie? nie robić ścieżek a'la Zend?

-- EDIT --

No i nie musiałbym zmieniać nazw klas w wypadku mapy smile.gif
cadavre
Ten czas naturalnie przy przetwarzaniu 100x. Ale i tak dużo - wiem. smile.gif Ten sposób naszedł mi na myśl bardziej dla celów 'rozrywkowych'. tongue.gif Jak już pisałem - ja tworzę mapę raz, zawsze po dodaniu klas / zmianach nazw itp. A właściwie to mapę tą tworzy parser po wywołaniu z panelu debugowania aplikacji. winksmiley.jpg
Athlan
Dobra, klamka zapadła, zdecydowałem się na sposób uzycia mapy. Teraz pytanie jak wygodnie ją zapisać. Oczywistością jest zaserializowanie jej, ale można inaczej. Mówie tu o pliku XML. możnaby było mieć mapę w pliku XML.

Plusy:
+ Przejżystość mapy
+ Łatwy dostęp za pomocą simplexml

Minusy:
- Opóźnienie działania poprzez stworzenie obiektu simplexml

Kwestia tablicy zaserializowanej:

Plusy:
+ Szybkość działania
+ łatwy dostęp do danych z poziomu aplikacji

Minusy:
- Przejżystość danych.

Który sposób wybrać? XML wolniejszy ale bardziej przejżysty, dokładnie odwrotne cechy ma zaserializowana tablica. Jaka jest Wasza opinia na ten temat? smile.gif

Pozdrawiam, Athlan smile.gif
dr_bonzo
Po co ci czytelna mapa -- ona ma byc czytelna tylko dla skryptu, wiec tylko serializacja.
mysz
Co do rozdzielania po wielkich literach: do tego łatwo wykorzystac preg_split" title="Zobacz w manualu php" target="_manual.
athabus
Co do odświeżania mapy i jej zerowania to ja zastosowałem prosty manewr. Otóż jeśli dana klasa znajduje się w mapie, a w między czasie zmienię jej lokalizację, to podczas próby jej podłączenia wyrzucam wyjątek - jeśli wyjątek się pojawi to po prostu czyszczę całą mapę.

BTW uważam, że przechowywanie całego rozkłada FW w mapie jest niepotrzebne - przecież w większości przypadków wykorzystujesz 30% klas - bardzo rzadko zdarza się sytuacja, że dany projekt wykorzystuje wszystkie klasy danego FW - po co zatem przechowywać całą mapę - ja u siebie zastosowałem automatyczne dodawania do mapy tylko tych plików, które są używane w danym projekcie - czyli te o które projekt poprosił chociaż raz. Oczywiście narzut na przetworzenie tego w przypadku małych FW gdzie jest dajmy 100 klas jest niezauważalny, ale ... jak optymalizować to od początku :-)
Athlan
Cytat
BTW uważam, że przechowywanie całego rozkłada FW w mapie jest niepotrzebne - przecież w większości przypadków wykorzystujesz 30% klas - bardzo rzadko zdarza się sytuacja, że dany projekt wykorzystuje wszystkie klasy danego FW - po co zatem przechowywać całą mapę - ja u siebie zastosowałem automatyczne dodawania do mapy tylko tych plików, które są używane w danym projekcie - czyli te o które projekt poprosił chociaż raz.

@athabus, no ale zobacz jakie są minusy. Jeżeli zmienię ścieżke jakiejś klasy, to mapa musi zostać kasowana we wszystkich aplikacjach korzystających z frameworka. Przetrzymywanie mapy dla danego projektu jest IMHO niepotrzebne. Szybciej stworzę mapę wszystkich komponentów, niż za każdym razem będę sprawdzał czy istnieje on na mapie i po użyciu jednej klasy więcej od razu muszę tworzyć nową mapę...

Postanowiłem, że mapę będzie trzymał sobie framework w swoim folderze obok klasy głównej smile.gif

Może teraz się wszyscy czepiamy, przecież to milisekundy, ale jakby tak rozumować to wogóle po co cache mapowania smile.gif

Cytat
jak optymalizować to od początku :-)

Dokładnie smile.gif

Pozdrawiam, Athlan smile.gif
athabus
Cytat(Athlan @ 21.01.2007, 12:57:30 ) *
@athabus, no ale zobacz jakie są minusy. Jeżeli zmienię ścieżke jakiejś klasy, to mapa musi zostać kasowana we wszystkich aplikacjach korzystających z frameworka. Przetrzymywanie mapy dla danego projektu jest IMHO niepotrzebne. Szybciej stworzę mapę wszystkich komponentów, niż za każdym razem będę sprawdzał czy istnieje on na mapie i po użyciu jednej klasy więcej od razu muszę tworzyć nową mapę...

Ale każdy projekt powinien mieć swoją własną mapę... Załóżmy że piszesz stronę dla swojej babci - coś ala blog. Wykorzystasz w nim 20 z 200 klas swojego FW - po co za każdym razem parsować te wszystkie klasy (w sensie plik z mapami do nich), skoro i taki ich nie używasz. Poza tym ja w mojej mapie przechowuje również informacje o klasach z danego projektu np. modele czy kontrolery itp, także jest to dodatkowy powód dla którego każdy projekt ma swoją mapę.

Cytat
Może teraz się wszyscy czepiamy, przecież to milisekundy, ale jakby tak rozumować to wogóle po co cache mapowania smile.gif


To już chyba taki styl życia :-)
dr_bonzo
Co rozumiem przez mape klas (to co w php Pro / Autoloader):
- jest to tablica $mapa[ 'NazwaKlasy' ] == 'sciezka/do/pliku/ZKlasa.php'
- tablice ta generuje sie automatycznie przegladajac skryptem tresc plikow z klasami

Cytat
ale ... jak optymalizować to od początku :-)

http://agilesoftwaredevelopment.com/blog/a...ation-is-the-ro

Zapewne niepotrzebnie sie narobisz.



Cytat
@athabus, no ale zobacz jakie są minusy. Jeżeli zmienię ścieżke jakiejś klasy, to mapa musi zostać kasowana we wszystkich aplikacjach korzystających z frameworka.

I co to za problem: svn up; i masz zupdatowany FW, potem ./create_class_map i masz mape klas.
Jarod
Cytat(Athlan @ 21.01.2007, 12:57:30 ) *
Postanowiłem, że mapę będzie trzymał sobie framework w swoim folderze obok klasy głównej smile.gif


Co u Ciebie robi kalsa główna?
Athlan
Cytat
Co u Ciebie robi kalsa główna?


Klasa główna, jest w pliku Vframe.Class.php, w którym przy okazji znajduje się __autoload() i error reporting (po co? aby ewentualnie logować błądy). Ma proste metody wyłącznie dla siebie (tworzenie mapy frameworka, zapisywanie w cache, pobieranie cache) oraz odpala całą hierarhię MVC (czytaj: tworzy front controller) w zależności od tego, kiedy sobie zażyczymy (bo np. nie zawsze porzebujkemy MVC smile.gif )

Poza tym moja klasa główna posiada register-registry, generuje stopkę frameworka (czas dzialania) gdy sobie tego zażyczymy. Potwafi wydumpować element oraz całą klasę za pomocą ReflectionClass::export(). Posiada proste metody typu: isUsable (czy plik jest gotowy do odczytu/zapisu), isReadable(), isWritable(). Sprawdza, czy najważniejsze stałe, które powinny znajdować się w konfigu aplikacji zostały przesłane.

I tutaj zgłaszam małe @todo, żeby nikt niepotrzebnie się nie czepiał: gdy nie używam MVC w aplikacji, stałe jego dotyczące i tak są sprawdzane - błąd do poprawy.

Klasa główna Vframe (wraz z cache'owaniem mapy) dostępna na listingu:

http://phpfi.com/196197

Pozdrawiam, Athlan smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.