Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [OOP] Klasa tylko z funkcjami statycznymi
Forum PHP.pl > Forum > PHP > Object-oriented programming
MiChaSSs
Hej,
Ostatnio zacząłem przepisywać skrypt na OOP i mam kilka funkcji (nie powiązanych ze sobą), które nie nadają się do standardowej klasy (gdzie tworzy się instancje obiektu) i tak sobie myslałem, czy byłoby prawidłowo jeślibym utworzył klasę (np. Tools czy Utilities) w której trzymałbym przydatne statyczne metody? Czyli stworzyłbym klasę, która nigdy nie będzie miała obiektu a będzie istniała tylko po to, żeby być kontenerem na statyczne metody. Coś na tej zasadzie:

  1. class Tools
  2. {
  3. public static function Metoda1()
  4. {
  5.  
  6. }
  7.  
  8. public static function Metoda2()
  9. {
  10.  
  11. }
  12. }
  13.  
  14. // Wywołanie metod
  15. Tools::Metoda1();
  16. Tools::Metoda2();


I teraz mam pytanie do Was ... ma to jakiś sens? biggrin.gif Jakie jest prawidłowe podejście? Czy funkcje powinny "luzem" w kodzie leżeć a ja nie powinienem za wszelką cenę opakowywać wszystkiego w OOP? Pozdrawiam MD
skowron-line
Helpery to klasy ze statycznymi metodami możesz zrobić taką klasę tylko z jedną metodą.
Crozin
Takie konstrukcje są pozbawione sensu z punktu widzenia OOP. Lepiej utwórz sobie odpowiednią przestrzeń nazw, a w niej zwykłe funkcje.
MiChaSSs
A istnieje jakis standard, który by definiował co w takim przypadku zrobić?
mike
Cytat(skowron-line @ 28.11.2010, 22:49:07 ) *
Helpery to klasy ze statycznymi metodami możesz zrobić taką klasę tylko z jedną metodą.
A niby dlaczego tylko z jedną metodą? Poza "helperami" masz też klasy narzędziowe. Jedna metoda na klasę to bezmyślność.
Cytat(Crozin @ 28.11.2010, 23:02:49 ) *
Takie konstrukcje są pozbawione sensu z punktu widzenia OOP. Lepiej utwórz sobie odpowiednią przestrzeń nazw, a w niej zwykłe funkcje.
Ale jednak nie da się ich uniknąć kiedy piszesz aplikację w duchu OOP.
Klasy narzędziowe to normalna sprawa, czasem są potrzebne i nie należy ich za wszelką cenę unikać.

Cytat(MiChaSSs @ 29.11.2010, 18:44:08 ) *
A istnieje jakis standard, który by definiował co w takim przypadku zrobić?
Klasa narzędziowa to dobre wyjście, jeśli tego faktycznie potrzebujesz. Jedyne co możesz zrobić dodatkowo to zamknąć ją na rozszerzanie i zablokować możliwość tworzenia instancji.
  1. <?php /* już nie pamiętam czy w PHP jest final */ final class Tools {
  2.  
  3. private Tools() {
  4. throw new Exception("IllegelStateException");
  5. }
  6.  
  7. // Jakieś funkcje
  8. }
  9.  
  10. ?>
skowron-line
Cytat(mike @ 30.11.2010, 09:44:40 ) *
A niby dlaczego tylko z jedną metodą? Poza "helperami" masz też klasy narzędziowe. Jedna metoda na klasę to bezmyślność.


Tak mi się napisało, poza tym helpery nie muszą być klasami statycznymi w Zend nie są.
marcio
Cytat
Tak mi się napisało, poza tym helpery nie muszą być klasami statycznymi w Zend nie są.

W symfony mamy funkcje typu include_partial() ktore w pewnym sensie tez sa helperami...wedlug mnie takie maja dzialanie poprostu zamykasz w funkcji/klasie czesto wykonywane czynnosci lecz niezbyt rozbudowane.

p.s oczywiscie jesli w klasie to jako metody statyczne
Zyx
Z funkcjami jest taki problem, że nie podlegają automatycznemu ładowaniu. Tutaj funkcjonalność OOP jest tylko narzędziem do uzyskania żądanych efektów, czyli funkcji + automatycznego ładowania.
aart3k
Reasumując: biorąc pod uwagę ograniczenia PHP (właśnie podane przez zyx'a) nie jest złym rozwiązaniem wrzucenie do klasy funkcji statycznych i niejako traktować klasę jak przestrzeń nazw.

Tak btw, jak masz dobrze zaprojektowany kod, to sytuacja w której chcesz utworzyć klasę Tools tylko ze statycznymi funkcjami nie ma prawa zaistnieć.
Quadina
Zgodzę się z użytkownikiem aart3k na prawie całej linii. Dobrze zaprojektowany model nie potrzebuje przestrzeni narzędzi. Jednak tak się czasem zdarza, że chcemy sobie różne rzeczy uprościć z punktu widzenia programistycznego obciążająć serwer. Dobrym przykładem jest tutaj helper Form z framework Symfony. Masz tam kupę funkcji generujących tylko i wyłącznie kod HTML, który bądź co bądź powinieneś generować samemu. A jednak w pewnych warunkach (np. dopuszczenie do szablonów php grafka) wymaga się takich a nie innych operacji. Wszystko zależy nie tylko od efektu jaki chcesz uzyskać, ale również od warunków. Ogólnie powtórze jak echo po aart3k: Dobrze zaprojektowany model nie potrzebuje takiego typu klas narzędziowych jak opisujesz.
Crozin
Hmmm... faktycznie brak autoloadera to już poważna wada (to nie jest ironia tylko przyznanie racji).

Cytat
Tak btw, jak masz dobrze zaprojektowany kod, to sytuacja w której chcesz utworzyć klasę Tools tylko ze statycznymi funkcjami nie ma prawa zaistnieć.
Ma prawo i takie coś jest powszechnie stosowane. Oczywiście można każdorazowo tworzyć nową instancję na zasadzie:
  1. $text = new StringUtils()->doSth($text); // PHP 5.4
  2.  
  3. $stringUtils = new StringUtils();
  4. $text = $stringUtils->doSth($text); // PHP < 5.4
Albo utworzyć sobie jakiś obiekt-kolekcję dla tego typu klas, który zwróci nam jedną automatycznie zainicjalizowany obiekt:
  1. $text = $this->getUtilClass('String')->doSth($text);
Ale skorzystanie z metod statycznych jest po prostu dużo wygodniejsze i czytelniejsze.
aart3k
@Crozin: you missed the point, chodziło o klasę Tools z narzędziami niepowiązanymi ze sobą.
athabus
Ja mam cały zbiór klas pomocniczych. Nazwałem go Cat - sam już nie pamiętam od czego to był skrót ;-) W nim mam klasy takie jak np.
Cat_Converter_String
Cat_Converter_Price
Cat_Converter_Array

Umieszczam je w każdym praktycznie projekcie, który robię. Np. po co tysiąc razy pisać metodę do przeliczania ceny brutto, naliczania rabatów, czy "slugowania" stringa jak można to umieścić w klasach pomocniczych. Jest to lepsze rozwiązanie, bo oszczędza czas i ogranicza głupie pomyłki.

Umieszczanie wszystkiego w modelu jest imo kiepskim pomysłem. Przykład nie będzie przeliczanie cen netto na ceny brutto - jeśli umieścisz to w modelu np. sklepu internetowego, gdzie robisz takie przeliczenia w wielu miejscach to po pewnym czasie mogą pojawić się niekonsekwencje typu:
- w jednym miejscu zaokrąglasz cenę a w drugim wartość produktów przez co otrzymujesz inne wyniki
- w przypadku dodania rabatu w jednym miejscu będziesz skracał dopiero wynik końcowy a w innym skrócisz raz po obliczeniu rabatu a następnie po obliczeniu ceny brutto - i znowu powstają groszowe niezgodności, które trudno potem wychwycić.

Mając wszystko scentralizowane łatwiej uniknąć takich głupich błędów. Ja osobiście lubię klasy z statycznymi metodami narzędziowymi i często korzystam. Autoloader też jest dla mnie ważny bo upraszcza kod.
thek
Może więc aart3k chodzi Ci o system helperów z Kohany? Bo nie wiem czy dobrze zrozumiałem. Podam przykład jednego z wbudowanych helperów Kohany:
  1. class security_Core {
  2.  
  3. public static function xss_clean($str)
  4. {
  5. return Input::instance()->xss_clean($str);
  6. }
  7.  
  8. public static function strip_image_tags($str)
  9. {
  10. return preg_replace('#<img\s.*?(?:src\s*=\s*["\']?([^"\'<>\s]*)["\']?[^>]*)?>#is', '$1', $str);
  11. }
  12.  
  13. public static function encode_php_tags($str)
  14. {
  15. return str_replace(array('<?', '?>'), array('&lt;?', '?&gt;'), $str);
  16. }
  17.  
  18. }
które wywołuje się statycznie nazwa_helpera::nazwa_metody(parametry)
Oczywiście w Kohanie nie istnieje jeden taki worek, ale takich klas jest wiele, zazwyczaj w sensowniejsze grupy poukładana. Jak zauważono, dobrze napisany skrypt nie potrzebuje ich, ale nieraz zamiast pisać kod od razu "ciurkiem" od razu poprawnie, wygodniej sobie takie klasy zdefiniować, by nie powtarzać co i rusz tego samego kodu, wielokrotnie długiego. Widząc niektóre jednak można się śmiać (patrząc na helper Array zobaczyć można ile to wywołania wariacji array_push/pop/shift czy innych wbudowanych), ale dla nie sięgających głębiej w bebechy frameworka takie pomocne dodatki są wybawieniem. Sam nieraz sobie pisze takie by przykładowo zamiast kilkunastu linijek kodu zgrabnie kod ująć jednym wywołaniem.
MiChaSSs
Okej, czyli poprawiając mój pierwszy, aby upewnić się że klasa nie będzie miała instancji, jej definicja powinna wyglądać tak:

  1. abstract class Tools
  2. {
  3. public static function Metoda1()
  4. {
  5.  
  6. }
  7.  
  8. public static function Metoda2()
  9. {
  10.  
  11. }
  12. }
  13.  
  14. // Wywołanie metod
  15. Tools::Metoda1();
  16. Tools::Metoda2();


Mam racje? Dziękuję wszystkim za pomoc, pozdrawiam MD
aart3k
nie wiem czy z abstracta można wywoływać statyczne.

@thek: Kohany nie znam, wiem zaś że rozwiązanie które opisałeś świetnie się sprawdza, niezależnie od stosowanego frameworka.
U siebie mam parę właśnie tego pokroju klas, niektóre mające tylko jedną funkcję, nie mniej jednak chodzi o to żeby były logicznie spójne np. mój MM_Geolocator ma tylko statyczną getCountryByIp.
mike
Cytat(MiChaSSs @ 1.12.2010, 17:36:28 ) *
Okej, czyli poprawiając mój pierwszy, aby upewnić się że klasa nie będzie miała instancji, jej definicja powinna wyglądać tak:
Po klasie abstrakcyjnen można odziedziczyć i wtedy utworzenie instancji stoi otworem.
Zrób klasę finalną z prywatnym konstruktorem, z którym rzucisz wyjątek tak jak pokazałem w poprzednim poście.
Cytat(aart3k @ 1.12.2010, 18:52:28 ) *
nie wiem czy z abstracta można wywoływać statyczne.
Można.
MiChaSSs
Cytat(aart3k @ 1.12.2010, 18:52:28 ) *
nie wiem czy z abstracta można wywoływać statyczne.


Abstract służy właśnie do tego, żeby nie trzeba było mieć instancji obiektu, aczkolwiek jak słusznie zauważył kolega mike nie oznacza to, że nie można po tym dziedziczyć. Dziękuję za Waszą pomoc, pozdrawiam MD
manro
Cytat(MiChaSSs @ 1.12.2010, 23:37:23 ) *
Abstract służy właśnie do tego, żeby nie trzeba było mieć instancji obiektu, aczkolwiek jak słusznie zauważył kolega mike nie oznacza to, że nie można po tym dziedziczyć. Dziękuję za Waszą pomoc, pozdrawiam MD

Abstract służy do tego żeby nie można było bezpośrednio z tej klasy stworzyć instancji obiektu, a nie do tego żeby nie trzeba było mieć instancji obiektu, jak sama nazwa wskazuje określa to abstrakcyjny model, którego instancja fizyczna nie istnieje. Pozwala to natomiast tworzenie konkretnych instancji obiektów danego typu np:

abstract class Animal {}
class Dog extend Animal {}
class Cat extend Animal {}
athabus
Dokładnie jak kolega wyżej pisze. Twoje zastosowanie abstract w sumie działa, ale nie jest do końca zgodne z ideą OOP - abstract ma bardziej pełnić rolę interfejsu, tyle że "rozbudowanego" o część metod.

Dzięki temu można np. stworzyć kolekcje obiektów o jednolitym interfejsie i np. po nich potem iterować.

Użycie klasy abstract w sposób jaki tutaj proponujesz jest niewłaściwe - mike podał ci eleganckie rozwiązanie zgodne z ideą OOP.
MiChaSSs
Cytat(manro @ 2.12.2010, 16:55:45 ) *
Abstract służy do tego żeby nie można było bezpośrednio z tej klasy stworzyć instancji obiektu, a nie do tego żeby nie trzeba było mieć instancji obiektu, jak sama nazwa wskazuje określa to abstrakcyjny model, którego instancja fizyczna nie istnieje. Pozwala to natomiast tworzenie konkretnych instancji obiektów danego typu np:

abstract class Animal {}
class Dog extend Animal {}
class Cat extend Animal {}


&&

Cytat(athabus @ 2.12.2010, 17:04:01 ) *
Dokładnie jak kolega wyżej pisze. Twoje zastosowanie abstract w sumie działa, ale nie jest do końca zgodne z ideą OOP - abstract ma bardziej pełnić rolę interfejsu, tyle że "rozbudowanego" o część metod.

Dzięki temu można np. stworzyć kolekcje obiektów o jednolitym interfejsie i np. po nich potem iterować.

Użycie klasy abstract w sposób jaki tutaj proponujesz jest niewłaściwe - mike podał ci eleganckie rozwiązanie zgodne z ideą OOP.

Tak, ja tylko tłumaczyłem co miałem na myśli pisząc wcześniej o abstract winksmiley.jpg Ale jak kolega mike zauważył po tym można dziedziczyć + konsekwencje tego, stąd pozostaje tylko to, co mike zaproponował wcześniej, pozdrawiam MD
smentek
Cytat(MiChaSSs @ 2.12.2010, 19:23:28 ) *
&&


Tak, ja tylko tłumaczyłem co miałem na myśli pisząc wcześniej o abstract winksmiley.jpg Ale jak kolega mike zauważył po tym można dziedziczyć + konsekwencje tego, stąd pozostaje tylko to, co mike zaproponował wcześniej, pozdrawiam MD



Wszystko pięknie tylko czemu ma to służyć? Kto i po co miał by tworzyć instancje z klasy posiadającej jedynie metody statyczne?
mike
Cytat(smentek @ 10.12.2010, 17:27:26 ) *
Wszystko pięknie tylko czemu ma to służyć? Kto i po co miał by tworzyć instancje z klasy posiadającej jedynie metody statyczne?
Żeby ograniczyć pomyłki lub dziwne pomysły programistów. Taki zabieg nic nie kosztuje a być może zaoszczędzi kwiatka w kodzie.
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.