![]() |
![]() |
![]()
Post
#1
|
|
![]() Grupa: Zarejestrowani Postów: 952 Pomógł: 154 Dołączył: 20.01.2007 Skąd: /dev/oracle Ostrzeżenie: (0%) ![]() ![]() |
Po długich perypetiach życiowych udało mi się wreszcie dokończyć pierwszą "normalną" bibliotekę z serii Open Power Libs 3. Nie jest ona może duża, ale ostatecznie nie zawsze potrzeba nam wielkich kobyłek. Tutaj wystawiam ją do publicznej oceny przez społeczność PHP.
Open Power Collector to uniwersalny interfejs do udostępniania różnych hierarchicznych danych. Można z niego zbudować system konfiguracji, albo np. gromadzić informacje o danym żądaniu HTTP. Jest on nastawiony na rozszerzanie i adaptację do nowych zastosowań. Uniwersalny interfejs dostępowy może dam całkiem dużo - nasz kod staje się dzięki temu niezależny od źródła danych konfiguracyjnych oraz tego, czym te dane tak właściwie są. Równie dobrze możemy je wczytywać z pliku konfiguracyjnego, generować dynamicznie na podstawie uprawnień, jak i w elegancki sposób testować w PHPUnit. Przykładowe użycie w roli zbieracza danych o żądaniu HTTP:
Przykładowe użycie w roli systemu konfiguracji:
Obecnie zaimplementowana funkcjonalność: - Możliwość gromadzenia i udostępniania danych hierarchicznych - Możliwość wyciągnięcia całej grupy opcji - Możliwość ładowania danych w dowolne miejsce hierarchii danych (tj. możemy dany plik konfiguracyjny doładować np. bezpośrednio do głównego poziomu, jak i podczepić jego zawartość pod jakiś węzeł). - Obsługa cache'owania przy pomocy niewydanego jeszcze Open Power Cache - Zestaw domyślnych ładowarek: * Do budowy systemu konfiguracji: ładowanie danych z plików YAML, XML, INI. * Do budowy zbieracza danych o żądaniu HTTP: informacje o zdalnym hoście, informacje o połączeniu. Planowana funkcjonalność: - Przyspieszenie dostępu do często używanych zagnieżdżonych opcji - Ładowanie wartości jednej opcji z innej opcji - Nowe ładowarki informacyjne o żądaniu HTTP; w szczególności chcę przeportować mechanizm rozpoznawania przeglądarki i systemu operacyjnego. * Kod + bugtracker: Github * Download * Dokumentacja Chętnie wysłucham kulturalnych opinii na temat tego projektu i możliwości jego dalszego rozwoju. Od razu też mówię: istnienie polskiej dokumentacji uzależnione jest od tego, czy ktoś ją po prostu przetłumaczy, przy czym ktoś != ja. -------------------- Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0 |
|
|
![]() |
![]()
Post
#2
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
FileLoader::__construct
Dlaczego nie "realpath" + .'/' ? FileLoader W FileLoaderze brakuje mi wsparcia dla ładowania wielu plików. Np mój katalog settings z plikami ini ma ich całkiem sporo, gdybym chciał użyć twojego loadera to musiałbym naprawde nieźle się nagimnastykować aby zadbać o ładowanie odpowiednich plików w odpowiednim czasie. LoaderyDynamiczne Warto by pomysleć nad loaderami dynamicznymi (jak już), ponieważ to co jest teraz nie ułatwia mi pracy ponieważ równie dobrze mogę używać loadFromArray gdzie podam swoje źródło loaderów. "no cache system installed"
Nie "installed" tylko "supplied" albo "assigned" i nie "cache system" tylko "cache object" coś w tym stylu. Aktualny komunikat jest mylący. Collector loadFromLoader Zapis
Skróciłbym do:
Chyba, że się mylę a wtedy łoj mnie równo XML
Nie wiem czy nie lepiej zwalidować takie rzeczy za pomocą .XSD, ale to już zależy od podejścia Cache Collectora Collector jest "Keszowalny", że tak to brzydko nazwę, a wtedy brakuje mi do tego odpowiednich interfejsów/u jak np "Cacheable", który wprowadziłem u Siebie. Przykładowe metody setCache(Interface_Cache $cache) getCache() setCacheKey($key); getcacheKey($key) setUseCache($useCache); // w formie dla vsprintf getUsecache(); // czasem nie chce cacheować obiekt tylko na jakis czas, ale po co wtedy usuwac obiekt Cache? generateCacheKey(array $parameters) Jednoznacznie oznacza nam czy klasa obsługuje Cache czy też nie. Aktualna obsługę cache można wywalić i lepiej zaimplementować interfejs Serializable a cacheowaniem zajmie się kto inny. Visit/* te dane raczej kompletnie nie nadaja się do "keszowania" moim zdaniem. FileLoaderMock Może nie jestem wybitnym specem od testów jednostkowych ale do czegoś takiego jest createMockForAbstractClass w PHPUnit-cie, jeżeli tego nie masz to https://github.com/sebastianbergmann/phpunit-mock-objects Dodatkowo nie wiem czy dobrą praktyką jest testowanie właściwości "wewnętrznych" klasy za pomocą takich "mocków". Jak już to na 100% brakuje mi metody getPaths w FileLoaderze. Nie uważam, jej za zbędną. A nawet gdyby jej nie było to nie wyobrażam sobie takiego testowania właściwości wewnętrznych, robisz to albo wykorzystując metody dostępne w klasie albo wcale (co jest raczej niemożliwe). Co do "terminologii" to nie wiem czy nawet słowo "mock" się tutaj nadaje, ponieważ jak dla mnie jest to raczej klasa "zasób" do testów (tak samo jak pliki testowe (xml-e, ini, yaml-e)), czekam na Twoją opinie. Provider Bardzo dobry pomysł z drugiem parametrem metody "get". Sam miałem z tym problem, który ostatecznie nie rozwiązałem. OGÓŁ Ogólnie bardzo dobra robota. Gdybym miał to oceniać to solidne 9/10. Nie sprawdzałem czy testy pokrywają 100% kodu ale to już mniejsza z tym. Aktualnie nie widzę większego sensu tego Collectora (bo brakuje dynamicznych loaderów). Osobiście nie użyję go, ale jako zastępca "Zend_Config" jak najbardziej OK. -------------------- |
|
|
![]()
Post
#3
|
|
![]() Grupa: Zarejestrowani Postów: 952 Pomógł: 154 Dołączył: 20.01.2007 Skąd: /dev/oracle Ostrzeżenie: (0%) ![]() ![]() |
Dzięki za wyczerpującą odpowiedź. Już odpowiadam na pytania i wątpliwości:
FileLoader::__construct() realpath() rozwija ścieżkę względną do absolutnej, co oznacza, że po prostu nie ma bata, ale musi on wykonywać powolne operacje dyskowe. Przy otwieraniu pliku i tak trzeba to porozwijać, ale wtedy system operacyjny zasadniczo wie, po co to rozwija i może to sobie jakoś (przynajmniej w teorii) zoptymalizować. Tymczasem jedyne czego potrzebuję to zwykły slash na końcu ścieżki i nic więcej. Ładowanie wielu plików To jest bardziej problem samego kolektora - ostatecznie musi on wiedzieć, w które miejsce drzewka zawartość każdego z tych plików podpiąć i naraz przetwarzać może tylko jedno źródło. Taką listę plików można zresztą wrzucić w tablicę i zapętlić:
Loadery dynamiczne O, dobrze że o tym wspomniałeś, bo zapomniałem o tym napisać. To też JEST planowane i nawet początkowo miało być od razu, ale doszedłem do wniosku, że najpierw lepiej jest zrobić stabilny podstawowy mechanizm, a później się bawić w jego rozbudowę o nowe bajerki, niż napakować za dużo i później się zastanawiać, jak zrobić, by to miało ręce i nogi. "no cache system..." OK, uwzględnione. Collector loadFromLoader Nie wiem, czy to właśnie nie zostało po pierwszym szkicu z dynamicznymi ładowarkami ![]() XML XSD to już jest potężna kobyła. Wczytanie schematu, jego przeparsowanie, a później użycie zajęłoby trochę czasu. Wprawdzie niby takie czytanie i tak powinno być cache'owane, ale po sesji z Symfony 1.x stwierdziłem, że wersja robocza projektu ładująca się np. 8 sekund zdecydowanie przekracza mój poziom cierpliwości i nawet tu wymagam pewnej wydajności ![]() ![]() Cache Collectora Wyszedłem tu z założenia, że: 1. w systemie najczęściej i tak jest jeden obiekt cache, 2. jak już tworzymy taki kolektor i wprowadzamy do niego cache, to raczej nie po to, by te wszystkie parametry zmieniać 50 razy w trakcie trwania żądania. 3. jak ktoś będzie potrzebować cache, to od tego ma różne kontenery wstrzykiwania zależności i inne zabawki, a nie kolektor ![]() Natomiast co do serializacji to masz rację. Taki interfejs na pewno się przyda, zarówno do różnych dziwnych zastosowań, o których mi się póki co nie śni, jak i do cache'owania, które można sobie po prostu obsłużyć zewnętrznie. Przy okazji zmniejsza się liczba zależności klasy. Visit/* I nikt nie zmusza Cię do ich cache'owania ![]() FileLoaderMock Że taka biblioteka jest, to wiem, bo bez niej trochę ciężko PHPUnit 3.5 zainstalować ![]() ![]() Ad. testowania wewnętrznych właściwości -> "teoria" testowania ma wprowadzony podział na tzw. testy czarnej skrzynki i testy białej skrzynki. W tym drugim przypadku znamy wewnętrzną budowę testowanego elementu i używamy jej. W pewnych sytuacjach biała skrzynka jest pewniejsza; mógłbym tutaj oczywiście użyć którejś z klas pochodnych, ale wtedy w teorii istnieje ryzyko, że funkcjonalność dodana przez taką klasę może zaburzyć to, jak dana metoda działa w rzeczywistości. Testując bezpośrednio klasę abstrakcyjną jestem wolny od potencjalnych skutków ubocznych wywołanych nadpisaniem. Wiem, że omawiany przypadek jest skrajnie debilny i nawet bym się zdziwił, gdyby takie rzeczy się tu działy, ale po prostu postąpiłem według konwencji. -------------------- Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0 |
|
|
![]()
Post
#4
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Ładowanie wielu plików
No właśnie dlatego nie użyłbym czegoś takiego bo... nie zawsze potrzebuję wszystkich konfiguracji z całego drzewa katalogu. Nawet jeżeli założeniem jest załadowanie całego drzewka to tworzenie takiej tablicy jest trudne. Lepiej dorobić metode "readEntireTree()", oczywiście wszystko zależy od twoich wewnętrznych założeń. Dlatego loadery dynamiczne ratują sytuację. xml Ze schemaValidate można wyciągnąć błędy
Oczywiście to była tylko sugestia, ponieważ też w większości przypadków nie używam .XSD ale też nawet nie zwracam informacji o błędach w XML, dlatego zwróciłem na to uwagę ![]() Visit/* Tak jasne, tylko troszkę zamydliło mi to koncepcję biblioteki. Z jednej strony ładujesz do niej pewne dane, które długi czas się nie zmienią (konfiguracje są raczej statyczne) a z drugiej dane typu HOST, IP których częstotliwość zmian jest bardzo duża. Po prostu dziwne miejsce na wykorzystanie pobierania TAKICH danych. A tym bardziej zapisywania ich w "cache" razem. Testy Co do teorii skrzynek to kiedyś o nich słyszałem, ale nie zapadło mi to w pamięć, aczkolwiek dzięki za przypomnienie choć nadal przystawałbym jednak do wersji "czarnej skrzynki" ![]() Zapomniałem dać jeszcze jednej pochwały. METHOD CHAINING! O dzięki, bo nadal wiele osób go nie używa ![]() Ale... brak mi go w loadFromLoader, loadFromArray (nie wiem, czy ktoś będzie nawet sprawdzał wynik tej metody, lepszy jest wyjątek - moim zdaniem). No i brakuje testu takiego czegoś. Niby pierd ale naprawdę dobry nawyk, który potrafi uchronić od wielu błędów
-------------------- |
|
|
![]()
Post
#5
|
|
![]() Grupa: Zarejestrowani Postów: 952 Pomógł: 154 Dołączył: 20.01.2007 Skąd: /dev/oracle Ostrzeżenie: (0%) ![]() ![]() |
Błędy z libxml2 wyciąga się kosz-mar-nie
![]() ![]() Generalnie z tą biblioteką było tak, że początkowo miała się nazywać Open Power Visitor i zbierać tylko dane o wizycie, ale tak później popatrzyłem na to, pomyślałem i wymyśliłem, że identyczny interfejs dostępu do opcji będzie w konfiguracji, w jakichś ustawieniach prywatności użytkownika, czy ustawieniach personalizacyjnych. To wszystko działa tak samo, według tej samej logiki, więc po co do każdego przypadku użycia mam wynajdować koło od nowa? Zrobię jeden uniwersalny interfejs + możliwość tworzenia własnych ładowarek i będę mieć gotowe 10 rzeczy za jednym zamachem ![]() Tak więc tutaj nie chodzi o to, czy dane zmieniają się nam co żądanie, czy raz na długi czas. Chodzi o to, że schemat pracy jest ten sam: wpychamy pewien zbiór informacji do tego kolektora, a później możemy sobie z niego w każdej chwili wygodnie czytać. Jeśli nam to jest potrzebne, to możemy go sobie scache'ować, ale to zależy tylko od nas i od konkretnego scenariusza zastosowania. Ad. method chaining/fluent interface -> jak tylko nie zapomnę z rozpędu, to dodaję ![]() -------------------- Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0 |
|
|
![]()
Post
#6
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Cytat Zrobię jeden uniwersalny interfejs + możliwość tworzenia własnych ładowarek i będę mieć gotowe 10 rzeczy za jednym zamachem smile.gif. Tak ale... bałbym się "rąbnięcia" czy czasem tego obiektu nie miałem wcześniej w Cache i co wtedy. Rozumiem, podejście "w jednym miejscu" ale idąc tym śladem, równie dobrze możesz tam trzymać obiekty modeli, formularzy, szablony itd. Nie zrozum mnie źle, nie ganie Cię za podejście, lecz tylko chciałbym zwrócić uwagę na ryzyko popełnienia błędu. Oczywiście "pro" nie będą mieli z tym większego kłopotu ale reszta... ciężko. W tym przypadku nie mam nic przeciwko gdyby nawet w Kontekście aplikacji albo też swoistemu rodzajowi "rejestrze" był sobie obiekt do zbierania danych wizyty bo TAM jest jego miejsce, STAMTĄD wiem, jaki obiekt zostanie zwrócony i dzięki TEMU obiektowi wiem jakie dane mogę pobrać (podpowiadanie IDE). Niepotrzebny mi jest wspólny interfejs. -------------------- |
|
|
![]()
Post
#7
|
|
![]() Grupa: Zarejestrowani Postów: 952 Pomógł: 154 Dołączył: 20.01.2007 Skąd: /dev/oracle Ostrzeżenie: (0%) ![]() ![]() |
Ale wtedy tworzysz sobie dwa kolektory - jeden do konfiguracji, drugi do zbierania danych o wizycie. Gdyby to były zupełnie osobne implementacje, to i tak miałbyś dwa obiekty, a dodatkowo miałbyś dwie osobne klasy do załadowania.
-------------------- Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0 |
|
|
![]() ![]() |
![]() |
Aktualny czas: 20.08.2025 - 14:57 |