Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Usuwanie podstrony/innej treści, Jak to wykonać zgodnie z obiektowością?
kiler129
post 21.07.2011, 14:22:15
Post #1





Grupa: Zarejestrowani
Postów: 566
Pomógł: 35
Dołączył: 21.06.2006

Ostrzeżenie: (0%)
-----


Witajcie!
Krótko i na temat - postanowiłem z lekka uporządkować kod swojego CMSu i uczynić go bardziej obiektowym. W związku z tym sprawdziłem jaki wpływa na prędkość ma zbudowanie obiektu i wykonanie metody kontra wykonanie metody statycznej, wyniki z lekka mnie zaskoczyły:
  1. <?php
  2. class test {
  3. static public function get() { return array(); }
  4. }
  5.  
  6. class test2 {
  7. public function get() { return array(); }
  8. }
  9.  
  10. $s = microtime(true);
  11. for($i=0; $i<=1000; $i++) {
  12. $x = new test;
  13. $y = $x->get();
  14. unset($x, $y);
  15. }
  16. echo "Object: ".round((microtime(true)-$s), 4)." ms<br/>";
  17.  
  18. $s = microtime(true);
  19. for($i=0; $i<=1000; $i++) {
  20. $y = test2::get();
  21. unset($y);
  22. }
  23. echo "Static: ".round((microtime(true)-$s), 4)." ms<br/>";
  24.  
  25. /*
  26.  Object: 0.0036 ms
  27.  Static: 0.0037 ms
  28. */
  29. ?>


Różnica praktycznie żadna a wg teorii OOP wykonujemy akcję na danym obiekcie więc chyba najsensowniejszym podejściem jest taka organizacja obsługi podstron:
  1. <?php
  2. class subpage {
  3. protected $id = NULL;
  4. protected $validId = false;
  5.  
  6. function __construct($id=NULL) {
  7. if($id > 0 && textOperations::isInt($id)) { //basic validation
  8. $this->validId = true;
  9. $this->id = $id;
  10. } else {
  11. $this->validId = false;
  12. }
  13. }
  14.  
  15. public static getList() { }
  16. public function get() { }
  17. public function delete() { }
  18. public function save($arrayWithParams) { }
  19. }
  20.  
  21. $page = new subpage(134);
  22. $x = $page->get();
  23. $page->delete();
  24. unset($page);
  25. ?>


Jedna z metod (akurat w tym przykładzie) jest niezależna od id podstrony bo defakto odnosi się nie do jednej a do listy podstron.
Zastanawia mnie natomiast jedna kwestia - czy obiektowo poprawnie będzie rozwiązać to tak:
  1. <?php
  2. class subpage {
  3. public static getList() { }
  4. public static function get($id) { }
  5. public static function delete($id) { }
  6. public static function save($id, $arrayWithParams) { }
  7. }
  8.  
  9. $x = subpage::get(134);
  10. subpage::delete(134);
  11. ?>


Druga metoda jest wygodniejsza w użyciu, prędkością się nie różni ale nie wiem czy jest to do końca poprawne.
Z góry dzięki za odpowiedź smile.gif


--------------------
flexiCMS v2 [|||||||+--] 75% done
Go to the top of the page
+Quote Post
Zyx
post 21.07.2011, 17:22:20
Post #2





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Masz błąd w teście: statycznie wywołujesz metodę niestatyczną i na odwrót, ale wyniki generalnie masz w miarę OK - wywołanie metod statycznych jest wolniejsze niż niestatycznych. Różnice nie są wprawdzie duże, ale są.

Elementy statyczne w klasach z formalnego punktu widzenia nie mają z programowaniem obiektowym nic wspólnego, ponieważ jak programowaniem obiektowym może być coś, gdzie nie mamy obiektów? Na dobrą sprawę nie wnoszą one zbyt wiele do większości języków programowania. W Javie są one nawet przydatne, ale dlatego, że nie ma tam w ogóle funkcji. W PHP ich zastosowanie ogranicza się wyłącznie do podlegania automatycznemu ładowaniu i modyfikatorom dostępu. Ja od jakiegoś czasu mam bardzo prostą zasadę:

* pól statycznych nie używam w ogóle,
* metody statyczne używam tylko wtedy, gdy naprawdę wiem, co robię i że mi naprawdę jest to potrzebne.

Poza tym wszystko jedzie na obiektach. Jeśli faktycznie cały mechanizm odpalania akcji będzie zgodny z zasadami projektowania obiektowego, to wtedy zauważysz, że Twój ostatni listing to nieporozumienie smile.gif.


--------------------
Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0
Go to the top of the page
+Quote Post
kiler129
post 21.07.2011, 17:54:41
Post #3





Grupa: Zarejestrowani
Postów: 566
Pomógł: 35
Dołączył: 21.06.2006

Ostrzeżenie: (0%)
-----


Faktycznie, strzeliłem błąd. Przy poprawnej notacji wyniki (dla 10 tys przejść) są już nieco bardziej sensowne:
Object: 0.0358 ms
Static: 0.0166 ms

Tutaj faktycznie logiczniej jest tworzyć obiekt i ew. zostawiać część metod statycznych. A jeśli chodzi o klasy z wszystkimi statycznymi metodami to wydaje mi się, że ma to sens w wypadku gdy coś jest często używane w dużej ilości miejsc kodu gdzie przekazywanie uchwytu nie daje korzyści a jest upierdliwe (np. klasa do cache).

Tylko teraz co z funkcjami typu getMultiById()? Wtedy jest to operacja niby nie na jednej podstronie a na wielu. Nijak tu nie pasuje podanie do konstruktora array(1,3,55,134) więc dobrze aby metoda sama w sobie przyjmowała listę idków jako argument.


--------------------
flexiCMS v2 [|||||||+--] 75% done
Go to the top of the page
+Quote Post
Zyx
post 21.07.2011, 20:19:11
Post #4





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Niestety nie są sensowne. Znalazłem kolejny błąd. Tworzenie obiektu nie jest częścią wywoływania metody - owszem, trzeba to zrobić, ale to robisz RAZ. Dlaczego zatem w pętli wliczasz do wywoływania metody czas tworzenia obiektu?

Cytat
Tutaj faktycznie logiczniej jest tworzyć obiekt i ew. zostawiać część metod statycznych.


Nie przekręcaj mojej wypowiedzi. Napisałem jasno, że metody statyczne powinniśmy tworzyć tylko wtedy, gdy wiemy co robimy, co oznacza, że 99% programistów nie powinno używać ich w ogóle. Nie mówię tu o braku umiejętności (chociaż z drugiej strony... smile.gif), ale o tym, że ich tak naprawdę w ogóle nie potrzebują. Twój problem akurat wybitnie należy do kategorii problemów, gdzie static nie ma żadnego logicznego uzasadnienia.

Cytat
A jeśli chodzi o klasy z wszystkimi statycznymi metodami to wydaje mi się, że ma to sens w wypadku gdy coś jest często używane w dużej ilości miejsc kodu gdzie przekazywanie uchwytu nie daje korzyści a jest upierdliwe (np. klasa do cache).


To źle Ci się wydaje. Argument "bo jest używane w dużej liczbie miejsc" to brednia do kwadratu, bowiem wtedy musiałbyś w ogóle przestać stosować obiektówkę do większości rzeczy. Co to w ogóle jest "uchwyt do klasy"? Z przykładem z cache też trafiłeś, jak kulą w płot - jest to jeden z fajniejszych tematów do modelowania obiektowego i robiąc tam wszystko statycznie byś go dokumentnie rozwalił.

Ogólnie powiem tak: znasz składnię, wiesz jak działają obiekty, klasy, elementy statyczne. Jednak to, że potrafisz dwie cegły spoić cementem, nie czyni jeszcze z Ciebie architekta. Umiesz używać klas i obiektów, natomiast o programowaniu obiektowym nie masz zielonego pojęcia. Co bym Ci radził na początek, to zostawienie CMS-a i rozpoczęcie od paru ćwiczeń, w trakcie których nie wolno Ci używać słów kluczowych global, static, extends (a i owszem) oraz metod, których nazwy zaczynają się od __, z wyjątkiem __construct() i __destruct(). Ba, powiem nawet więcej: modelując system, powinieneś wręcz zapomnieć o pojęciu klasy, bowiem jak sama nazwa programowanie obiektowe wskazuje, operujemy tu na obiektach i tylko na obiektach, a klasa to jedynie wygodny schemat do tworzenia obiektów o podobnych zadaniach. Co, że restrykcyjne? Nie, to jest istota programowania obiektowego ogołocona ze wszystkich ogłupiaczy. Dopiero gdy się tego nauczysz, będziesz wiedział, że cała reszta to zwykły lukier składniowy i pomoc, która jednak jest pomocą tylko wtedy, gdy znajduje się w doświadczonych rękach.


--------------------
Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0
Go to the top of the page
+Quote Post
Spawnm
post 21.07.2011, 20:55:17
Post #5





Grupa: Moderatorzy
Postów: 4 069
Pomógł: 497
Dołączył: 11.05.2007
Skąd: Warszawa




A weź teraz Zyx uzasadnij czemu Kiler129 nie powinien używać extends.
Może jeszcze powiedz jak miał by uczyć się tworzenia klas abstrakcyjnych bez extends.
Go to the top of the page
+Quote Post
kiler129
post 21.07.2011, 20:58:20
Post #6





Grupa: Zarejestrowani
Postów: 566
Pomógł: 35
Dołączył: 21.06.2006

Ostrzeżenie: (0%)
-----


Czyli kolejna rzecz przewróciłeś mi w głowie Lkingsmiley.png
Która metoda jest tutaj w takim razie poprawna:

Kod
//Metoda #1
$x = new page;
$x->id = 123;
$x->get();
$x->id = 13;
$x->get();
$x->id = 30;
$x->delete();
unset($x);

//Metoda #2
$x = new page(123);
$x->get();
$x = new page(13);
$x->get();
$x = new page(30);
$x->delete();
unset($x);


Co do cytatu to bardziej odnosił się do moich przemyśleń a nie do twojej wypowiedzi smile.gif
Kiedy więc static ma logiczne uzasadnienie? Cache wydaje mi się tutaj dobrym przykładem bo używam w dużej liczbie miejsc niepowiązanych ze sobą np. core_cache::get("news", 13); - php inicjuje sobie w środku jedną kopie i ja mam z głowy dbanie jak się do niej odwołać (nie muszę mieć czegoś w stylu $GLOBALS["cacheObj"] = new core_cache;)

Jeśli chodzi o moją znajomość obiektówki to się z tobą w 100% zgadzam: wiem jak co działa ale już żeby to logicznie zaprojektować to z tym gorzej. Problem jest jednak taki, że nie mam za bardzo czasu na dokładne teoretyczne studiowanie tego tylko uczę się przy okazji stałego rozwijania CMSu (który bądź co bądź na mnie zarabia poniekąd).

Czy mógłbyś naświetlić mi jak powinna (oczywiście szablonowo) wyglądać klasa obsługująca dostęp do newsów czy to podstron uwzględniając to, że można pobrać ich kilka na raz?


--------------------
flexiCMS v2 [|||||||+--] 75% done
Go to the top of the page
+Quote Post
Zyx
post 21.07.2011, 21:08:11
Post #7





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Tobie też by się takie ćwiczenie przydało, skoro napisałeś taki post smile.gif. W jednym masz rację: słowo abstract też powinno znaleźć się na liście słów zakazanych, bo bez extends nie ma sensu smile.gif.

A czemu, przecież napisałem:

Cytat
(...) to jest istota programowania obiektowego ogołocona ze wszystkich ogłupiaczy. Dopiero gdy się tego nauczysz, będziesz wiedział, że cała reszta to zwykły lukier składniowy i pomoc, która jednak jest pomocą tylko wtedy, gdy znajduje się w doświadczonych rękach.


Programowanie obiektowe to nie są klasy abstrakcyjne, static czy extends. To sposób myślenia i projektowania. Dopóki ktoś się go nie nauczy, będzie jedynie programistą, który umie używać klas oraz dziedziczenia i nic poza tym. Klasy abstrakcyjne, dziedziczenie i cała reszta to jedynie narzędzia i lukier składniowy. OK, dziedziczenie nie do końca się do tego zalicza, ale akurat jest jedną z bardziej zwodniczych koncepcji. Naucz się najpierw dobrze podstaw, a później siadaj za pulpitem sterowniczym elektrowni jądrowej.

--- [odpowiedź dla kilera] ----

Który sposób będzie tam poprawny? Nie ma na to pytanie jednej odpowiedzi, może poza tym, że ID to ja bym jako argument przekazywał, jeśli już smile.gif. Zapytasz się mnie, co w sytuacji, gdy identyfikacja wiersza wymaga większej liczby pól, a ja Ci odpowiem: niech argument z identyfikatorem będzie obiektem implementującym interfejs Identifier. Wtedy sobie zaimplementujesz różne typy identyfikatorów, jakie masz w aplikacji i będziesz mógł nimi operować w sposób uniwersalny. To jest właśnie przykład obiektowego podejścia.

A dlaczego żadnemu z Twoich sposobów nie można nadać etykietki "poprawny"/"niepoprawny"? Ponieważ tutaj to już tak naprawdę zależy od tego, co chcesz zrobić i co te Twoje obiekty mają reprezentować. Metoda #2 to zwykłe mapowanie obiektowo-relacyjne, gdzie obiekty reprezentują jeden wiersz w bazie. Jest to popularne, zwłaszcza w zastosowaniach typu CRUD, natomiast do bardziej zaawansowanych rzeczy ja preferuję metodę #1 ze wspomnianą już modyfikacją, ponieważ jest ona bardziej ogólna i mniej przekombinowana w przypadku złożonych schematów.

Co do przykładu z cache, to wyjaśnij mi, czym to, co zrobiłeś, różni się od wywołania funkcji np. apc_get(), albo zwykłego wstawienia global? Ja Ci już podpowiem prawidłową odpowiedź, że absolutnie niczym. Przede wszystkim kto powiedział, że potrzebujesz dokładnie jeden obiekt cache'u? Pomyśl. Cache'ujemy różne rodzaje danych, różne rodzaje danych mają różne wymagania (cykliczne aktualizacje, aktualizacje na żądanie, dłuższe, krótsze itp. itd.)? Wprowadzasz tu pojęcie zasobu (np. "konfiguracja", "dane", "kod HTML"), polityki (czyli jakiej funkcjonalności oczekujesz od cache'u) oraz strategii (czyli już konkretna implementacja). Politykę kodujesz jako interfejs, strategię jako klasę implementującą ten interfejs, a zasób jako pytanie do menedżera obiektów strategii "panie, podaj mi tu obiekt, który potrafi cache'ować zasób z rodziny 'konfiguracja'". Dostajesz obiekt, upewniasz się co do obsługiwanej przez niego polityki, robisz operacje i po sprawie. Chcesz zmienić strategię dla konkretnego zasobu, w menedżerze rejestrujesz dla niego inną strategię i tyle.

Cytat
Problem jest jednak taki, że nie mam za bardzo czasu na dokładne teoretyczne studiowanie tego tylko uczę się przy okazji stałego rozwijania CMSu (który bądź co bądź na mnie zarabia poniekąd).


Dlatego radzę Ci, byś zostawił tego CMS-a w takim kształcie, jak on jest (ew. nie bawił się tu na razie w obiektówkę), a zaoszczędzony czas poświęcił na jakieś prostsze ćwiczenia. Szkoda marnować i wspomniany czas, i CMS-a nieudolną przebudową. CMS Ci nie ucieknie, a dzięki temu później zrobisz go lepiej i szybciej. Ja np. bardzo żałuję, że w czasach, gdy miałem swoje pierwsze próby z klasami (11 lat temu), nie było nikogo, kto by mi powiedział to, co napisałem teraz Tobie, przez co mnóstwo mojej pracy poszło na marne.

Ten post edytował Zyx 21.07.2011, 21:30:14


--------------------
Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0
Go to the top of the page
+Quote Post
Spawnm
post 21.07.2011, 21:19:46
Post #8





Grupa: Moderatorzy
Postów: 4 069
Pomógł: 497
Dołączył: 11.05.2007
Skąd: Warszawa




Zyx, on powinien ćwiczyć korzystanie z extends właśnie po to by wiedzieć kiedy, czy i jak z niego korzystać.
Niech się bawi w klasy np. rodzic auto i dzieci fiat, matiz.
Niech wie że matiz nie dziedziczy po db mysql itp. wink.gif
Go to the top of the page
+Quote Post
Zyx
post 21.07.2011, 21:42:43
Post #9





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Spawnm... rodzic "auto" i dzieci "fiat, matiz"... to jest przecież jeden ze sztandarowych przykładów, jak się z dziedziczenia nie powinno korzystać. Właśnie perfekcyjnie teraz widać, jak to się ludzie uczą, kiedy "extends" wykorzystywać, pakując je wszędzie, gdzie się da. I co, jak będziesz chciał dodać kolejną markę, to będziesz nową klasę pisał oraz przebudowywał całą aplikację? I co, jak do "auta" dodasz jakąś nową funkcjonalność, będziesz wszystkie klasy pochodne przerabiał i od nowa testował, by się upewnić, że wszystko jest OK? I co, później zrobisz na bazie tych klas aplikację do zarządzania typami aut i w momencie gdy użytkownik zauważy, że przypadkiem zły typ ustawił, odpowiesz mu "sorry, nie możesz teraz tego zmienić, bo ja już utworzyłem obiekt"? To się załatwia, robiąc obiekty klasy "Pojazd" trzymające referencje do obiektów klasy "TypPojazdu".

Ten post edytował Zyx 21.07.2011, 21:43:22


--------------------
Specjalista ds. głupich i beznadziejnych, Zyx
Nowości wydawnicze: Open Power Collector 3.0.1.0 | Open Power Autoloader 3.0.3.0
Go to the top of the page
+Quote Post
LSM
post 21.09.2011, 15:43:20
Post #10





Grupa: Zarejestrowani
Postów: 64
Pomógł: 6
Dołączył: 20.03.2011
Skąd: Świdnica

Ostrzeżenie: (0%)
-----


"[...] jak się z dziedziczenia nie powinno korzystać."
A ja uważam, że powinien używać extends jeśli chce zobaczyć na czym polega obiektowość. Nauka polega na tym, że popełnia się błędy i wyciąga z nich wnioski. Po za tym nie można nigdy polegać na tym co powie Ci ktoś kto ma doświadczenie - bo różni programiści mają bardzo różne doświadczenia. Jeśli ktoś chce być świadomy to musi przejść przez etap - używania i odrzucania lub też nie. Wtedy kształtuje się własne zdanie, a samo doświadczenie jest bogatsze. Używanie extends jest to temat rzeka, i nigdy nie wiadomo gdzie się przyda, a gdzie będzie zbyteczne, o tym decyduje charakter pisanej aplikacji i problem, który rozwiązujemy, a często również nasze "widzi mi się" czyli to jak patrzymy na nasze własne prywatne i skromne rozwiązanie problemu.

Jeśli to co robię w kodzie jest poparte paroma argumentami Za, i jednym przeciw - to z reguły używam tego rozwiązania. Czasami łatwiej jest użyć extends i zaoszczędzić czas niż stracić czas i odrazu super uelastycznić aplikację. Początkowa wersja programu wg. mnie nie powinna mieć super architektury, bo ciężko jest określić w jakim kierunku pójdą zmiany. A tworzenie od samego początku super super architektury może w pewnych przypadkach być wadą aplikacji.


--------------------
"I see" - said the blind man.
Go to the top of the page
+Quote Post
CuteOne
post 24.09.2011, 13:12:13
Post #11





Grupa: Zarejestrowani
Postów: 2 958
Pomógł: 574
Dołączył: 23.09.2008
Skąd: wiesz, że tu jestem?

Ostrzeżenie: (0%)
-----


Zyx:: i w tym momencie zabiłeś mi ćwieka smile.gif patrząc na kod Zenda i na to co napisałeś dostałem małego zawrotu głowy. Hmm, może jak znajdziesz chwile wolnego czasu mógłbyś przedstawić na jakimś prostym przykładzie kiedy należy używać dziedziczenia?

ps. powinieneś założyć bloga i pisać w nim artykuły na takie tematy wink.gif
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 23.04.2024 - 23:12