Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [OOP] klasy i funkcje
Forum PHP.pl > Forum > PHP > Object-oriented programming
zzeus
Czytałem kilka podobnych wątków ale nigdzie nie znalazłem jednoznacznej odpowiedzi. Załóżmy że mamy zdjęcia, napisaliśmy sobie klasę Zdjecie która obsługuje zdjęcia. Jak jednak pobrać 100 zdjęć ? Stworzyć funkcję która pobiera pobiera z bazy info o tych zdjęciach i zwrócić jako tablicę, stworzyć funkcję która zwróci tablicę 100 obiektów typu zdjęcie, stworzyć metodę w klasie Zdjecie która pobierze z bazy i zwróci w postaci tablicy dane o 100 zdjęciach ? Jak rozwiązujecie taki problem ?

Pozdrawiam
erix
Cytat
Jak rozwiązujecie taki problem ?

Możesz wykorzystać tu interfejs Iterator. Nie męczysz za bardzo pamięci, a dodatkowo wygodniej.
zzeus
Chodzi mi o coś takiego, że czasami potrzebuje pobrać 100 zdjęć, czasami 20 a czasami 3. Dodatkowo nie zawsze potrzebuje wszystkie dane o zdjęciu, np. czasami nie potrzebuje wiedzieć jakie ma wymiary. Jednocześnie chciałbym aby dane o zdjęciu były zawsze prezentowany w ten sam sposób. Więc jak to uzyskać ? Napisać 3 funkcje, które pobiorą z bazy za pomocą odpowiedniego zapytania interesujące mnie dane, i na ich podstawie tworzyć obiekt typu zdjęcie, który sobie ustawi tylko te pola dla których dostanie wartości ?

No i czy w przypadku kiedy pobieram te dane o iluś tam zdjęciach tylko po to aby je wyświetlić na stronce, to czy opłaca się tworzyć np. 100 obiektów typu zdjęcie tylko po to aby za chwilę zwróciły one dane w postaci tablicy ? Czy od razu ładować poprostu dane do tablicy bez tworzenia obiektu i przekazać do smarty ?

Pozdrawiam
erix
Cytat
Napisać 3 funkcje, które pobiorą z bazy za pomocą odpowiedniego zapytania interesujące mnie dane, i na ich podstawie tworzyć obiekt typu zdjęcie, który sobie ustawi tylko te pola dla których dostanie wartości ?

Przy konstruowaniu klasy podajesz w tablicy, które dane chcesz uzyskać.

Cytat
No i czy w przypadku kiedy pobieram te dane o iluś tam zdjęciach tylko po to aby je wyświetlić na stronce, to czy opłaca się tworzyć np. 100 obiektów typu zdjęcie tylko po to aby za chwilę zwróciły one dane w postaci tablicy ?

A czy przeczytałeś mojego poprzedniego posta?
zzeus
A mógłbyś podać jakiś przykład, bo chyba nie do końca rozumiem.
Tworzę sobie iterator, nakazuje mu pobrać 12 zdjęć

  1. <?php
  2. $_objPhoto = new Photo();
  3. $iterator = new Iterator($_objPhoto->getPhoto(), 12);
  4. while($photo = $iterator->next())
  5. {
  6.  $_arrPhotos[] = $photo;
  7. }
  8. ?>


Czy to miałoby wyglądać mniej więcej tak ?
W takim przypadku wykonuje 12 zapytań do bazy danych, i tworzę 12 obiektów klasy Photo. Chyba że się mylę ?
W przypadku funkcji mogę pobrać 12 zdjęć w jednym zapytaniu i zwrócić w postaci tablicy, takiej samej jaką tutaj otrzymam.
karmer
Witam,
stwórz sobie klasę "galeria", która będzie miała prywatną tablicę obiektów "photo". W klasie "galeria" umieść metody operujące na zbiorze zdjęć, np. wczytywanie zdjęć do obiektu galerii, pobieranie z niej zdjęć i inne operacje, które sobie wymarzysz.

Pozdrawiam
zzeus
Cytat(karmer @ 19.12.2008, 22:16:51 ) *
Witam,
stwórz sobie klasę "galeria", która będzie miała prywatną tablicę obiektów "photo". W klasie "galeria" umieść metody operujące na zbiorze zdjęć, np. wczytywanie zdjęć do obiektu galerii, pobieranie z niej zdjęć i inne operacje, które sobie wymarzysz.

Pozdrawiam


To chyba jest okrojona wersja Iteratora smile.gif
erix
  1. <?php
  2. class klasa implements Iterator{
  3.  
  4. //
  5.  
  6. }
  7.  
  8. $c = new klasa;
  9.  
  10. foreach($c as $obrazek){
  11. echo $obrazek->src;
  12. }
  13. ?>


Odpowiednie funkcje, których powinieneś użyć w klasie, są opisane w Sieci, rusz się. tongue.gif
karmer
Klasa galerii może dla Twojej wygody implementować interfejs Iteratora. Zrobienie jednak z galerii "czarnej skrzynki" byłoby dla mnie bardziej wygodne. Udostępniasz metody "galerii" na zewnątrz (musisz przemyśleć jakie moetody byłyby przydatne dla użytkownika takiej klasy) a resztę zamykasz wewnątrz. Potem możesz modyfikować 'bebechy' takiej klasy bez zmiany jej interfejsu. Bo np. gdybyś chciał z jakichkolwiek powodów zrezygnować z interfejsu iteratora to co wtedy? Ktoś kto umieścił Twoją klasę galerii we własnym projekcie musiałby zmieniać swój kod.
erix
Cytat
Bo np. gdybyś chciał z jakichkolwiek powodów zrezygnować z interfejsu iteratora to co wtedy?

A niby czemu miałby rezygnować? Masz na myśli jakiś konkretny powód?
karmer
Nie miałem na myśli konkretnego przypadku. Raczej dla zachowanie idei hermetyzacji i przenośności. Teoretycznie interfejs iteratora też może się kiedyś zmienić, albo może być zastąpiony innym rozwiązaniem. Wiem, że to mało prawdopodobne :-). W/g mnie klasa galerii z udostępnionym iteratorem byłaby raczej "obiektem kontenera zdjęć" a nie obiektem galerii. I mogłaby wtedy posłużyć jako rdzeń galerii.
erix
To może w ogóle nie używajmy SPL? Bez przesady, bardziej prawdopodobne, że zostaną dodane nowe interfejsy do biblioteki niż usunięte.

Nie używaj wyjątków, bo też zostaną zmienione. Najbardziej mnie boli w przypadku projektowania aplikacji dla PHP5 takie oporne korzystanie z SPL, no nie mogę tego znieść. A potrafią odwalić kawał dobrej roboty (choćby iteracja rekursywna - coś, co klepało się dziesiątkami linijek sprowadza się do max kilku i do tego z dużo większą wydajnością).

Wyjdźmy z ciemnogrodu PHP4.
zzeus
Poszukałem, poczytałem i chyba mam rozwiązanie.
Klasa Kolekcja, która będzie służyła jako swego rodzaju tablica do przechowywania obiektów. Klasa IteratorKolekcji która będzie służyć do iterowania kolekcji przekazanej jako parametr. Będzie można tworzyć potomków klasy Kolekcja precyzując typ obiektów które można będzie przechowywać. Do tego wzorzec Factory dla klasy Zdjecie, czyli klasa FactoryZdjecie która będzie zawierała statyczne metody pobierające odpowiednie dane z bazy danych, tworzyła na ich podstawie obiekty i nimi wypełniała kolekcję. W klasie Kolekcja zaimplementowana leniwa konkretyzacja, która będzie wybierała odpowiednią metodę z FactoryZdjecie.

Co o tym myślicie ?

Pozdrawiam
Cysiaczek
Nie rozumiem, dlaczego chcesz rozdzielić kolekcję od klasy służącej do jej przeglądania? Tu akurat klasa kolekcji implementująca Iterator jest idealnym rozwiązaniem. Do tego kolekcja może mieć metody getAll(), getNumberOfPhotos($nb), findById() itp. Każdy załadowany obiekt powinien być umieszczony w kolekcji, aby następne odwołanie do niego nie powinno skutkować kolejnym zapytaniem do bazy. Lepiej zatem używać kolekcji od razu, a fabrykę umieścić w jej wnętrzu.
  1. <?php
  2. $c=new PhotoGallery();
  3. $photo=$c->findById(1);
  4. $photo2=$c->findById(2);
  5. $c2=$c->getSelectedPhotos(); // np może zwracać kolejną kolekcję :)
  6. ?>


Pozdrawiam
zzeus
Takie rozwiązanie było akurat opisane w książce z której korzystam, ale po głębszej analizie doszedłem do wniosku że faktycznie nie ma potrzeby rozdzielania kolekcji od klasy która będzie ją iterować. Ale co do umieszczenia fabryki we wnętrzu kolekcji to nie bardzo wiem o co chodzi.

Pozdrawiam
Cysiaczek
Możesz rozdzielić wszystko. Pytanie tylko, czy poniesiony koszt Ci się zwróci?
W teorii dobrym rozwiązaniem jest:
Gallery
PhotoCollection
PhotoFactory
Photo
phpion
Cytat(Cysiaczek @ 20.12.2008, 15:49:08 ) *
Gallery
PhotoCollection

Jaka jest różnica (teoretyczna) między tymi dwoma klasami? smile.gif
zzeus
No więc robię tak:
Photo - klasa przechowująca dane o zdjęciu i posiadająca metody operujące w bazie danych jeśli chodzi o jedno zdjęcie
PhotoCollection - rozszerzenie Collection, zaimplementowana leniwa konkretyzacja i iterator
PhotoFactory - statyczne metody pobierające z bazy danych zdjęcia o określonych parametrach (zdjęcia danego użytkownika, zdjęcia z danej kategorii)

To tyle, jak chodzi o mój pomysł. Co można zmienić aby było lepiej ?
Do czego miałaby służyć klasa Gallery ?

Pozdrawiam
Cysiaczek
Jako interfejs - nakładka na wymienione przez Ciebie obiekty.
zzeus
Cytat(Cysiaczek @ 20.12.2008, 15:20:28 ) *
Jako interfejs - nakładka na wymienione przez Ciebie obiekty.


Możesz coś więcej napisać ? Jak by to wyglądało ?

Pozdrawiam
Cysiaczek
PhotoCollection to po prostu obiekt kolekcji z podstawowymi metodami add, remove, get. Gallery w tym modelu to taki punkt dostępu do funkcji - żeby ich w ciele akcji nie pisać, tylko wywołać.
  1. <?php
  2. $g=new Gallery();
  3. $g->getFilesCreatedBefore($time);
  4. $g->getPhoto(1) // szuka w kolekcji
  5. $g->findPattern('*.jpg');
  6. ?>

itp.
Tylko jak pisałem - nie zawsze trzeba tak dużo abstrakcji robić, bo jest to nieopłacalne, jeśli wykonujemy np tylko podstawowe operacje na plikach czy wpisach w bazie.

Pozdrawiam
zzeus
ok, mam już napisane klasy:
Collection
CollectionPhoto
Photo
PhotoFactory

Mam jednak mały problem, w klasie Collection jest metoda

  1. <?php
  2. setLoadCallback($funkcja, $obiektLubKlasa)
  3. ?>


Metoda ta korzysta z call_user_func(), i obecnie służy do podawania metody którą należy wywołać z photoFactory aby wypełnić kolekcję (można też korzystać w inny sposób ale to teraz nie ważne). Jednak metody w photoFactory mają różną liczbę parametrów z którymi je wywołuje, i nie wiem zabardzo jak zmodyfikować setLoadCallback żeby przekazywać różną liczbę parametrów. Bo pisanie dla każdej metody z photoFactory odpowiadającej jej metody setLoad... chyba mija się z celem ?

Pozdrawiam
Crozin
Użycie call_user_func_array" title="Zobacz w manualu PHP" target="_manual umożliwia Ci podanie w niej listy parametrów w tablicy (a przez docelową metodę/funkcje odczytanie tego "normalnie").

W setLocalCallback tworzysz zmienną ilość parametrów, zbierasz je func_get_args" title="Zobacz w manualu PHP" target="_manual, dwa pierwsze indeksy (0, 1) to $funkcja, $obiektLubKlasa. Następnie array_slice" title="Zobacz w manualu PHP" target="_manualm usuwasz je i pozostałe elementy tablicy przekazujesz jako 2-gi param call_..._array()
zzeus
Chyba prościej będzie poprzez call_user_func_array() ?
Crozin
No, ale przecież to napisałem winksmiley.jpg
Cysiaczek
No nie - użyłeś call_user_func()/
zzeus
Cytat(Cysiaczek @ 21.12.2008, 11:41:10 ) *
No nie - użyłeś call_user_func()/


A co w tym złego ?
Crozin
  1. <?php
  2.  
  3. class Collection{
  4.    public function setLoadCallback(){
  5.        $args = func_get_args();
  6.        
  7.        if(count($args) < 2){
  8.            throw new Exception('...');
  9.        }
  10.        
  11.        $method = $args[0];
  12.        $obj    = $args[1];
  13.        
  14.        $args = array_slice($args, 2);
  15.        
  16.        call_user_func_array(array($obj, $method), $args);
  17.    }
  18. }
  19.  
  20. class SampleClass{
  21.    public function sampleMethod($param1, $param2, $param3){
  22.        var_dump($param1);
  23.        var_dump($param2);
  24.        var_dump($param3);
  25.    }
  26. }
  27.  
  28.  
  29. try{
  30.    $sc = new SampleClass();
  31.  
  32.    $c = new Collection();
  33.    $c->setLoadCallback('sampleMethod', $sc, 'param1', 23, 'param3');
  34. }catch(Exception $e){
  35.    var_dump($e);
  36. }
  37. ?>
zzeus
No tak właśnie teraz mam, ale martwi mnie troszkę to że trzeba pamiętać o kolejności parametrów w funkcji i w takiej samej kolejności podać je w tablicy. Ale reszta działa całkiem fajnie smile.gif

Pozdrawiam

Cytat(Cysiaczek @ 20.12.2008, 17:01:04 ) *
PhotoCollection to po prostu obiekt kolekcji z podstawowymi metodami add, remove, get. Gallery w tym modelu to taki punkt dostępu do funkcji - żeby ich w ciele akcji nie pisać, tylko wywołać.
  1. <?php
  2. $g=new Gallery();
  3. $g->getFilesCreatedBefore($time);
  4. $g->getPhoto(1) // szuka w kolekcji
  5. $g->findPattern('*.jpg');
  6. ?>

itp.
Tylko jak pisałem - nie zawsze trzeba tak dużo abstrakcji robić, bo jest to nieopłacalne, jeśli wykonujemy np tylko podstawowe operacje na plikach czy wpisach w bazie.

Pozdrawiam


Inaczej mówiąc chodzi Ci o zastosowanie wzorca fasady ?

Pozdrawiam
Cysiaczek
Tak, o fasadę właśnie. Zwłaszcza, jeśli uczyni ona korzystanie z kodu bardziej ludzkim.
zzeus
No w sumie skróciło by to np. kod wyświetlenia zdjęć z 4 do 2 linijek.
Teraz jest np. tak:

  1. <?php
  2. $_objPhotoCollection = new PhotoCollection();
  3. $_arrParam = array($dbConnection, $_intSite);
  4. $_objPhotoCollection->setLoadCallback('getAllPhotos', 'photoFactory', $_arrParam);
  5. echo $_objPhotoCollection->toArray();
  6. ?>


a byłoby tak:

  1. <?php
  2. $_objGallery = new Gallery($dbConnection);
  3. $_objGallery->getAllPhotos($_intSite);
  4. ?>


Czy dobrze rozumię zasadę działania fasady ?
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.