Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Kilka pytań o praktyczne zastosowanie programowania obiektowego
Forum PHP.pl > Forum > PHP
Stron: 1, 2
Zagiewa
Witam. Dopiero wchodzę w programowanie obiektowe i choć oczytałem się już trochę, wiele poradników dostępnych w internecie opisuje obiektowość w sposób teoretyczny nie pokazując jak można go wykorzystać w praktyce dlatego też mam parę pytań, które nie dają mi spokoju.

1. Tworząc klasy powinno się je trzymać w tym samym pliku co całość kodu czy najlepiej jest utworzyć nowy plik zawierający tylko klasy, a następnie je includować w plikach w których będziemy z tych klas korzystać?
2. Jeśli utworzymy klasę to tworzenie do niej obiektów za pomocą np. formularzy jest proste (przynajmniej teoretycznie) natomiast jak zapisywać obiekty do bazy danych? zapisujemy samą nazwę obiektu czy należy zapisać nazwę wraz ze wszystkimi właściwościami tego obiektu? Np. mamy klasę o nazwie prostokąt. Właściwościami będzie bok_a i bok_b. Tworzymy nowy obiekt o nazwie pierwszy_prostokat i nadajemy mu właściwości bok_a=5 i bok_b=10 jak powinien wyglądać rekord gdy zapiszemy ten obiekt do bazy? bo mi przychodzą do głowy taki zapis:

id. || nazwa || bok_a || bok_b
1 || pierwszy_prostokat || 5 || 10

3. Czy nawet w przypadku prostych skryptów warto używać obiektowości? Dajmy na to tworząc księgę gości to ilość kodu niezależnie czy użyjemy kodu strukturalnego czy obiektowego jest niemal taka sama. Jeśli chodzi o czytelność jest też podobnie bo skrypt ogólnie jest prosty. Sposób zapisywania do bazy jest identyczny zmienia się co najwyżej struktura tabeli. Więc nasuwa się pytanie - jak pisać?
tmka
Na początek dobra rada jeżeli chodzi o sam proces nauki obiektówki i, w sumie, nauki czegokolwiek smile.gif - zobaczyć jak to robią inni. Poszukaj jakiś prostych CMS-ów, sklepów itp. napisanych obiektowo i zobacz jak robią to inni.

Jeżeli chodzi o pytania:
1. Najczęstszym modelem jest trzymanie każdej, nawet małej, klasy w oddzielnym pliku.
2. Użyte przez Ciebie pojęcie 'zapisu obiektu do bazy' jest troche mylące, bo zapisujesz tylko jego, i to niektóre, właściwości (w tym przypadku boki). Najlepiej zobrazuje to przykład:

  1. class Prostokat{
  2. private bokA;
  3. private bokB;
  4. private nazwa;
  5.  
  6. public function __construct(a,b,nazwa){
  7. $this->setBokA(a);
  8. $this->setBokB(b);
  9. $this->setNazwa(nazwa);
  10. }
  11.  
  12. public function setBokA(a){
  13. $this->bokA = a;
  14. }
  15.  
  16.  
  17. public function setBokB(b){
  18. $this->bokB = b;
  19. }
  20.  
  21.  
  22. public function setNazwa(nazwa){
  23. $this->nazwa = nazwa;
  24. }
  25.  
  26. public function getBokA(){
  27. return $this->bokA;
  28. }
  29.  
  30.  
  31. public function getBokB(b){
  32. return $this->bokB;;
  33. }
  34.  
  35.  
  36. public function getNazwa(){
  37. return $this->nazwa;
  38. }
  39.  
  40. //save zapisuje nam wlasciwosci do bazy
  41. public save(){
  42. //zalozmy, ze masz juz polaczenie, wiec tworzysz zapytanie ktore moze wygladac tak:
  43. $query = "INSERT INTO prostokaty ( nazwa, bok_a, bok_b ) VALUES ($this->nazwa, $this->bokA, $this->bokB)";
  44. mysql_query($query);
  45. }
  46. //load wczyta nam wlasciwosci z bazy, wystarczy podac id wpisu
  47. public load($id){
  48. //
  49. $query = "SELECT nazwa, bok_a, bok_b FROM prostokaty WHERE id=$id";
  50. $result = mysql_query($query);
  51. //itd.
  52. }
  53.  
  54. }


3. Na łatwych skryptach można łatwo przećwiczyć sobie pewne mechanizmy obiektowości jak np. dziedziczenie czy polimorfizm. Osobiście staram sie wszystko pisac obiektowo, ze wzgledu na to, że pozniej
łatwiej jest taki obiekt wykorzystać w innych projektach.
Zagiewa
Szukałem skryptów napisanych obiektowo ale na ogół natrafiałem na skomplikowane ogromne skrypty, których samo przeanalizowanie było gorsze niż nauka obiektowości tongue.gif Najbardziej w przykładzie, który napisałeś zainteresował mnie sposób zapisu i odczytu z bazy bo zrobiłeś z tego metody o czym ja raczej bym nie pomyślał. Sposób ten jest o tyle dobry, że bardzo prosto się odczytuje obiekt z bazy. Co do praktyki używania obiektowości nawet w prostych skryptach to masz racje, jest to dobry sposób na potrenowanie tak czy inaczej dzięki wielkie, nie oczekiwałem tak konkretnej odpowiedzi smile.gif
red9skull
To ja się podepnę: Do czego można wykorzystać konstruktor? Jak i kiedy z niego korzystać?
croc
Programowanie obiektowe pojawiło się, ponieważ jest bardziej naturalnym przełożeniem rzeczywistości na kod. Dla mnie używanie kodu obiektowego jest pewnego rodzaju dojrzałością programistyczną, chociaż używanie go wszędzie też nie jest rozsądne. Trzeba samemu wiedzieć co i kiedy jest właściwe.

Ja osobiście lubię tworzyć dużo metod tak, by używanie kodu było potem jak najbardziej intuicyjne i wygodne. Przykładowo:

  1. $article = new Article(12); // w konstruktorach robię pobieranie ID i wczytywanie danych z bazy do pól obiektu
  2. echo $article->getAuthor()->getFullName();
  3. if($article->getAuthor()->isAdmin()) {
  4. echo 'Autor jest administratorem!';
  5. }
  6. while($news = $article->getAuthor()->getNews()) {
  7. echo $news->getTitle();
  8. echo '<br>';
  9. echo $news->getDate()->getYear();
  10. }


Napisałem ten kod teraz, naprawdę nigdy tego konkretnego fragmentu nie użyłem. Chodzi o to jak pisać kod, żeby było można wykonywać równie wygodne operacje. Wszystko może być obiektem (u mnie np. daty to obiekty, bo potem bardzo fajnie się na nich operuje).

Nie wyobrażam sobie pisania dużych systemów strukturalnie. OK, samo pisanie sobie wyobrażam, ale potem rozwijanie kodu to masakra.
Zagiewa
Croc co prawda nie napisałem jeszcze żadnego praktycznego kodu z użyciem obiektowości bo tak jak pisałem dopiero staram się go dobrze zrozumieć ale zgodzę się, że rozbudowywanie kodu strukturalnego to koszmar tym bardziej, że kod strukturalny miejscami jest bardziej zawiły niż obiektowy, a przynajmniej tak mi się wydaje.
haahh
Strukturalny faktycznie strasznie się edytuję. Sam zmieniałem ostatnio strukturę wyświetlania mojego "małego portalu" php i to była masakra. Muszę przejść na obiektowy styl pisania kodu - ktoś poleci jakieś książki traktujące o średnio-zaawansowanym php i pisanie obiektowym?
croc
Lepsze są tutoriale. Zacznij od tutoriala o samej idei OOP nawet jeśli wydaje ci się, że ją znasz.

Co do zawiłości: nie uważam, by kod obiektowy był zawiły. Jest go dużo, ale dobrze napisany jest niesamowicie schludny i poukładany. Pamiętam dzień, kiedy przekonałem się do OOP w PHP - od tego czasu każdy projekt to dla mnie 90% mniej nerwów i irytacji. Pisząc kod, płyniesz. smile.gif Masz ten komfort, że kod w klasach można [przeważnie] poprawić bez ingerencji w schematy użycia tych klas. A to genialne, bo cały bajzel pojawia się zwykle w strukturach. Dla mnie najlepszą nauką OOP była nauka Javy, chociaż kompilowane aplikacje OOP pisze się nieco inaczej niż interpretowane.
haahh
Tutki? Pewnie najlepszy ten z manuala snitch.gif, coś polecasz? Ale i tak jakaś książka mi się przyda, bo chciałbym ruszyć do przodu z php. Zobaczę, może uda mi się mój portal przerobić na wersję obiektową i ciekawe, czy naprawdę będzie to lepiej się prezentować niż obecna wersja. Na razie za każdym razem jak spojrzę na te strzałki "->" to padam.
croc
Kiedyś kochałem czytać książki programistyczne, ale mam o nich coraz gorsze zdanie. Szalę goryczy przelała książka autorstwa samego ojca PHP pt. "PHP5. Programowanie". Byłem w szoku, że sam autor PHP utrwala złe nawyki (np. używanie funkcji empty dla stringów, co uważam za zły nawyk), niekonsekwencję w kodzie i bezsensowne podrozdziały kosztem takich, których brakuje w książce.

A zachwycając się dalej programowaniem obiektowym, to te strzałeczki również polubisz smile.gif (chociaż Bóg jeden wie dlaczego w PHP nie są to kropki) Kod daje frajdę, bo myślisz o wielu rzeczach jak o żywych obiektach, dzięki czemu zachowujesz konsekwencję. Oczywiście, strukturalnie mógłbyś robić do wszystkiego funkcje, ale to nie to samo.
thek
Czemu strzałeczki, a nie kropki? Może są to wskaźniki na pola, a nie same pola bezpośrednio. Albo zrobiono tak by nie przeciążać już używanego operatora konkatenacji.
$obiekt.pole
$obiekt.$pole
Różnica niewielka, ale trzeba by rozpoznawać po stronie interpretera z czym mamy do czynienia. Łatwiej wprowadzić -> , który jest bardziej jednoznaczny i wiąże się w pewien sposób z obiektami jako odniesienie przez wskaźnik typowe dla choćby takich języków jak C++.

EDIT: Patrząc na zapisy oba popatrz też jak łatwo się pomylić winksmiley.jpg Po prostu brak dolara w jednym miejscu.
red9skull
Cytat(thek @ 25.06.2010, 11:13:38 ) *
Czemu strzałeczki, a nie kropki?


Tak samo jak: czemu kropki a nie znak plusa?
  1. $string = "wyszukiwarka " . "google";


winksmiley.jpg
Zagiewa
Mam zamiar dzisiaj napisać pierwszy skrypt za pomocą obiektowości. Żeby było łatwo ale praktycznie padło na księgę gości. Zanim jednak zacznę chciał bym zapytać was czy dobrze ją sobie zaplanowałem, a więc.

1. klasa nazywała by się ksiega
2. właściwości: data, imie, email, strona, numer gg, komentarz
3. metody: zapis(do bazy), wczytaj(z bazy), set(ustawienie wartości dla właściwości)

I tutaj mam jeszcze dwa pytanka. tmka Ty jako pierwszą metodę utworzyłem z konstruktorem dlaczego? i czy ona jest wymagana? W Twoim kodzie ustawianie wartości dla właściwości jest w nowej metodzie np:
Kod
public function setBokA(a){

$this->bokA = a;

}

Moje pytanie to czy nie lepiej było by w jednej metodzie zawrzeć wszystkie właściwości czyli coś takiego:
Kod
public function setBokA(a){

$this->data = a;
$this->imie = b;
$this->email = c;
$this->strona = d;
$this->gg = e;
$this->komentarz = f;

}

Czy jest coś jeszcze o czym powinienem pamiętać przy pisaniu tego skryptu?
Mikz
Cytat(thek @ 25.06.2010, 11:13:38 ) *
Czemu strzałeczki, a nie kropki? Może są to wskaźniki na pola, a nie same pola bezpośrednio. Albo zrobiono tak by nie przeciążać już używanego operatora konkatenacji.
$obiekt.pole
$obiekt.$pole
Różnica niewielka, ale trzeba by rozpoznawać po stronie interpretera z czym mamy do czynienia. Łatwiej wprowadzić -> , który jest bardziej jednoznaczny i wiąże się w pewien sposób z obiektami jako odniesienie przez wskaźnik typowe dla choćby takich języków jak C++.

EDIT: Patrząc na zapisy oba popatrz też jak łatwo się pomylić winksmiley.jpg Po prostu brak dolara w jednym miejscu.


No nie jest to takie proste jeśli dorzucimy do tego fakt, że można zastosować coś takiego jak metoda __toString() w obiekcie lub nazwę funkcji jako wartość zmiennej winksmiley.jpg .

Red9skull, konstruktor można wykorzystać na wiele sposobów, na przykład:

  1.  
  2. class article
  3. {
  4. private $title, $content, $id;
  5.  
  6. public function __construct($id = null)
  7. {
  8. $this->id = $id;
  9.  
  10. if (!is_null($id))
  11. {
  12. $query = "SELECT * FROM articles WHERE 'id' = $id LIMIT 1";
  13.  
  14. $result = mysql_query($query);
  15. //pominę fetch etc...
  16.  
  17. $this->title = $result['title'];
  18. $this->content = $result['content'];
  19. }
  20. }
  21.  
  22. public function setTitle($title)
  23. {
  24. //parę postów wyżej było
  25. }
  26.  
  27. public function setContent($content)
  28. {
  29. //parę postów wyżej było
  30. }
  31.  
  32. public function save()
  33. {
  34. if (!is_null($this->id))
  35. $query = "UPDATE (et cetera)";
  36. else
  37. $query = "INSERT (et cetera";
  38.  
  39. //parę postów wyżej było
  40. }
  41. }
  42.  


Teraz pytanie z mojej strony, raczej z czystej ciekawości bardziej niż z potrzeby odpowiedzi:
Do czego najczęściej używacie destruktorów?
thek
Odpowiedź równe prosta - zwalniania zasobów przydzielonych konstruktorem. Dla wielu wyda się to dziwne, skoro istnieje Garbage Collector.Tu jest jednak pułapka. Wielokrotnie zachodzą sytuacje gdy pewne obiekty zawierają inne obiekty a te z kolei inne obiekty prowadzące do kolejnych. GC potrafi się w takich sytuacjach "wywalić" i zostawić w pamięci śmieci. Po prostu może czegoś nie zgarnąć do usunięcia. Taki zombie... Nie żyje, a jednak jest winksmiley.jpg O ile w PHP nie jest to łatwo zauważalne, tak w językach kompilowanych potrafi napsuć krwi. Szczególnie ważne jest to w dynamicznym przydziale pamięci. Jeśli pole jest tylko wskaźnikiem (adresem elementu) na obszar pamięci, to jego skasowanie powoduje nie usunięcie całej danej z pamięci, ale tylko utratę wskaźnika, bez dotykania tych danych. Jeśli obiekt jest tymczasowym tylko w pętli, to z każdym jej przebiegiem z pamięci ucieka nam obszar równy jej długości. Kilkadziesiąt tysięcy cykli i nagle program zająć może kilkadziesiąt MB, choć używa tak naprawdę kilkuset kilobajtów. Destruktory właśnie odpowiadać mają za zwalnianie pamięci w odwrotnej kolejności niż przydzielał ją konstruktor by uniknąć wycieków. To jest jego główne zadane, ale nie tylko. Często stosuje się parę konstruktor-destruktor do działania na zmiennych statycznych. Takim banalnym przykładem jest licznik obiektów. Konstruktor inkrementuje zmienną statyczną mającą być licznikiem obiektów. Bo przecież do takiej mają dostęp wszystkie obiekty tej samej klasy. Destruktor tę zmienną dekrementuje. Dzięki temu patrząc na zmienną statyczną, wiemy w każdej chwili ile instancji danej klasy siedzi w pamięci.
Mikz
Muszę się szczerze przyznać że nowością jest dla mnie fakt że PHP może nie radzić sobie ze zwalnianiem zasobów. Nigdy, na swoim przypadku, nie zaobserwowałem czegoś takiego i nigdy też nie stosowałem samodzielnego zwalniania zasobów w destruktorach (bo rozumiem że mówisz o samodzielnym zwalnianiu). Czy mógłbyś podrzucić jakiś przykład takiego zwalniania?
Crozin
Wystarczy użyć zwykłego unset.
thek
Jak wspomniał Crozin - unset. Co do destruktora to wiele osób odpuszcza sobie pisanie go w przypadku mało skomplikowanych klas. Zazwyczaj bowiem domyślne destruktory bezproblemowo radzą sobie z usuwaniem. Jeśli struktura jest zagmatwana lub niszczenie obiektu powinno zakończyć się określonymi działaniami, to własny destruktor po prostu ratuje tyłek. Nieważne bowiem jak kończy żywot obiekt - destruktor zostanie wywołany i wykona zadaną akcję, przykładowo zapis stanu obiektu do bazy lub pliku w momencie zniszczenia.
Zagiewa
Pisałem, pisałem, aż stanąłem w miejscu sad.gif Niby bez błędu a jednak przesyłane wartości nie trafiają do bazy. Mam dwa pliki. Jeden z klasą, drugi z formularze do dodawania wpisów w prostej księdze gości. Przypominam, że to mój pierwszy skrypt z zastosowaniem obiektowości. Mógł by ktoś zerknąć na moje wypociny i sprawdzić czemu to nie działa?
  1. <?php
  2.  
  3. class ksiega {
  4.  
  5. private $_data = null;
  6. private $_godzina = null;
  7. private $_imie = null;
  8. private $_email = null;
  9. private $_strona = null;
  10. private $_gg = null;
  11. private $_wpis = null;
  12.  
  13. public function ustaw_wartosci($data, $godzina, $imie, $email, $strona, $gg, $wpis) {
  14.  
  15. $this->_data = $data;
  16. $this->_godzina = $godzina;
  17. $this->_imie = $imie;
  18. $this->_email = $email;
  19. $this->_strona = $strona;
  20. $this->_gg = $gg;
  21. $this->_wpis = $wpis;
  22. }
  23.  
  24. public function pokaz() {
  25.  
  26. return $this->_data.'\n';
  27. return $this->_godzina.'\n';
  28. return $this->_imie.'\n';
  29. return $this->_email.'\n';
  30. return $this->_strona.'\n';
  31. return $this->_gg.'\n';
  32. return $this->_wpis.'\n';
  33. }
  34.  
  35. public function save() {
  36.  
  37. include('dane.php');
  38. $sql = mysql_connect(SQL_HOST, SQL_USER, SQL_PASS) or
  39. die("Sprawdź połączenie z serwerem! " . mysql_error());
  40.  
  41. mysql_select_db(SQL_DB, $sql) or
  42. die("Sprawdź bazę! " . mysql_error());
  43.  
  44. $insert = "INSERT INTO wpisy (data, godzina, imie, email, strona, gg, wpis)
  45. VALUES ('$this->data', '$this->godzina', '$this->imie', '$this->email', '$this->strona', '$this->gg', '$this->wpis')";
  46. $result = mysql_query($insert) or
  47. die('Dodanie wpisu nie powiodło się. ' . mysql_error());
  48. }
  49.  
  50. public function load_one($id) {
  51.  
  52. $select = "SELECT * FROM wpisy WHERE id=$id";
  53. $result = mysql_query($select) or
  54. die('Załadowanie wpisu z bazy nie powiodło się. ' . mysql_error());
  55. }
  56.  
  57. public function load_all() {
  58.  
  59. $select = "SELECT * FROM wpisy ORDER BY id DESC ";
  60. $result = mysql_query($select) or
  61. die('Załadowanie wpisów z bazy nie powiodło się. ' . mysql_error());
  62. }
  63. }
  64.  
  65. ?>

  1. <html>
  2. <head>
  3. </head>
  4. <body>
  5.  
  6. <?php
  7.  
  8. if(isset($_POST['submit'])) {
  9.  
  10. include('class/wpis.php');
  11.  
  12. $data = date("d-m-Y");
  13. $godzina = date("G:i");
  14. $imie = $_POST['imie'];
  15. $email = $_POST['email'];
  16. $strona = $_POST['strona'];
  17. $gg = $_POST['gg'];
  18. $wpis = $_POST['wpis'];
  19.  
  20. $nowy = new ksiega;
  21. $nowy->ustaw_wartosci($data, $godzina, $imie, $email, $strona, $gg, $wpis);
  22. $nowy->save();
  23.  
  24. echo 'Dziękuję za dodanie wpisu do księgi gości.';
  25. exit();
  26. }
  27.  
  28. ?>
  29.  
  30. Aby dodać wpis do księgi wypełnij formularz.
  31. <br /><br />
  32.  
  33. <form method="post">
  34. Autor: <input type="text" name="imie" size="25"><br />
  35. Email: <input type="text" name="email" size="25"><br />
  36. Strona www: <input type="text" name="strona" size="25"><br />
  37. Numer gg: <input type="text" name="gg" size="25"><br />
  38. Komentarz: <textarea style="width: 250px; height: 150px;" name="wpis"></textarea><br />
  39. <input type="submit" name="submit" value="Dodaj">
  40. </form>
  41.  
  42. </body>
  43. </html>
thek
Po pierwsze - użyj właściwego bbcode (nie wal do znacznika code, ale php i na przyszłość odpowiednio css, html czy inne). Poza tym nie wiemy jaki bład Ci sypie, a to też ważna informacja. Ja obstawiam, że funkcja save i błąd zapytania wpisującego do bazy. Ale to tylko przypuszczenie z mojej strony.
phpion
  1. class ksiega {
  2.  
  3. private $_data = null;
  4. private $_godzina = null;
  5. private $_imie = null;
  6. private $_email = null;
  7. private $_strona = null;
  8. private $_gg = null;
  9. private $_wpis = null;
  10.  
  11. //...
  12. }

Zastanowiłbym się nad sensownością powyższego kodu. Czy obiekt klasy ksiega faktycznie posiada takie elementy jak data, godzina itd.? Moim zdaniem nie, księga gości jest kolekcją wpisów, czyli powyższe składowe powinny być raczej w klasie wpis, a klasa ksiega powinna mieć jakąś składową typu tablicowego, w której byłyby obiekty wpisów. Wydaje mi się to sensowniejsze.
Mikz
Cytat(phpion @ 28.06.2010, 09:55:28 ) *
powyższe składowe powinny być raczej w klasie wpis, a klasa ksiega powinna mieć jakąś składową typu tablicowego, w której byłyby obiekty wpisów. Wydaje mi się to sensowniejsze.


Oczywiście pod warunkiem że zakładamy na jednej stronie więcej niż jedną księgę smile.gif.
Zagiewa -> zrób następująco a potem obejrzyj zapytanie ew. wklej je do phpmyadmina:

  1. // (...)
  2. public function save() {
  3.  
  4. include('dane.php');
  5. $sql = mysql_connect(SQL_HOST, SQL_USER, SQL_PASS) or
  6. die("Sprawdź połączenie z serwerem! " . mysql_error());
  7.  
  8. mysql_select_db(SQL_DB, $sql) or
  9. die("Sprawdź bazę! " . mysql_error());
  10.  
  11. $insert = "INSERT INTO wpisy (data, godzina, imie, email, strona, gg, wpis)
  12. VALUES ('$this->data', '$this->godzina', '$this->imie', '$this->email', '$this->strona', '$this->gg', '$this->wpis')";
  13. echo '<pre>';
  14. echo $insert;
  15. echo '</pre>';
  16. //POWYŻSZE 4 LINIE!
  17. $result = mysql_query($insert) or
  18. die('Dodanie wpisu nie powiodło się. ' . mysql_error());
  19. }
  20. // (...)


Koniecznie pamiętaj jeszcze o mysql_real_escape_string() żeby zabezpieczyć swój skrypt przed atakiem Sql Injection, inaczej każdy bardziej rozgarnięty szesnastolatek zrobi z Twoją bazą danych wszystko co będzie chciał.

Dzięki za przydatne odpowiedzi dotyczące unsetów smile.gif. W sumie dawno nie robiłem w "czystym" phpie, ostatnio się babram głównie w symfony ale wracam teraz do samego phpa i piszę coś w rodzaju frameworka/silnika i to mi się z całą pewnością przyda.
phpion
Cytat(Mikz @ 28.06.2010, 11:23:30 ) *
Oczywiście pod warunkiem że zakładamy na jednej stronie więcej niż jedną księgę smile.gif.

Chyba nie do końca wiesz o czym piszesz.
Zagiewa
thek sorki za te bbcode - już poprawiłem.
phpion mniej więcej rozumiem o co Ci chodzi ale nie był bym w stanie czegoś takiego zrobić haha tongue.gif jak sam widzisz jest to mój pierwszy taki skrypt (miał być prosty) i już są problemy tongue.gif Pytasz czy obiekt posiada takie elementy jak data i czas, tworząc tą klasę uznałem, że tak bo w momencie dodawania wpisu tworzony jest obiekt, do zmiennej jest zapisywany czas i data dodania a cały obiekt z tymi dwiema wartościami trafia do bazy jak dla mnie to ma sens.
Mikz Zrobiłem tak jak mówiłeś i oto co wypluła przeglądarka:
Kod
INSERT INTO wpisy (data, godzina, imie, email, strona, gg, wpis)
VALUES ('', '', '', '', '', '', '')

ok wiem, że brak wartości ale czemu? przecież przesyłam wartości, a przynajmniej tak mi się wydaje. Co do funkcji, którą mi podałeś przed atakami SQL Injection to dzięki, później sobie ją przerobie:)
Dobra, poradziłem sobie z tym. Dzięki Mikz za naprowadzenie. Wystarczyło w metodzie save() dodać podkreślenia _ przed zmiennymi/referencjami (tak to właściwie nazwać?) a wygląda to tak:
  1. public function save() {
  2.  
  3. include('dane.php');
  4. $sql = mysql_connect(SQL_HOST, SQL_USER, SQL_PASS) or
  5. die("Sprawdź połączenie z serwerem! " . mysql_error());
  6.  
  7. mysql_select_db(SQL_DB, $sql) or
  8. die("Sprawdź bazę! " . mysql_error());
  9.  
  10. $insert = "INSERT INTO wpisy (data, godzina, imie, email, strona, gg, wpis)
  11. VALUES ('$this->_data', '$this->_godzina', '$this->_imie', '$this->_email', '$this->_strona', '$this->_gg', '$this->_wpis')";
  12.  
  13. $result = mysql_query($insert) or
  14. die('Dodanie wpisu nie powiodło się. ' . mysql_error());
  15. }

Mam jeszcze takie pytanie. Czy w moim kodzie metoda ustaw_wartości działa poprawnie? Wydaje mi się, że tak bo gdy by metoda ta nie ustawiła wartości to metoda save nie mogła by zapisać wartości do bazy mam rację?
phpion
Cytat(Zagiewa @ 28.06.2010, 13:31:18 ) *
phpion mniej więcej rozumiem o co Ci chodzi ale nie był bym w stanie czegoś takiego zrobić haha tongue.gif jak sam widzisz jest to mój pierwszy taki skrypt (miał być prosty) i już są problemy tongue.gif Pytasz czy obiekt posiada takie elementy jak data i czas, tworząc tą klasę uznałem, że tak bo w momencie dodawania wpisu tworzony jest obiekt, do zmiennej jest zapisywany czas i data dodania a cały obiekt z tymi dwiema wartościami trafia do bazy jak dla mnie to ma sens.

Ok, ale odpowiedz sobie na pytanie: co dodajesz do bazy? Księgę czy wpis? Sam zresztą napisałeś:
Cytat(Zagiewa @ 28.06.2010, 13:31:18 ) *
w momencie dodawania wpisu tworzony jest obiekt, do zmiennej jest zapisywany czas i data dodania a cały obiekt z tymi dwiema wartościami trafia do bazy

Jak widzisz dodajesz obiekt wpisu, a nie księgi. Księga zawiera w sobie wpisy (obiekty wcześniej dodanych wpisów). Piszesz o umiejętnościach, że się uczysz: w takim razie od razu ucz się dobrego podejścia, a nie pseudo-obiektowego.
Zagiewa
No tak dodaję wpis, więc według Ciebie powinna być klasa o nazwie baza a jej wartościami klasa o nazwie wpis i co jeszcze? jak poprawnie powinno to wyglądać? Tworząc moją klasę wydawało mi się, że dobrze ją zaplanowałem, a obecnie jak wspomniałeś o dwóch klasach, nie mam pojęcia jak one miały by wyglądać aby były poprawne.
phpion
To powinno Ci nieco rozjaśnić sytuację:
  1. class Wpis {
  2. protected $data;
  3. protected $tresc;
  4.  
  5. public function dodaj() {
  6. // Zapis do bazy danych
  7. }
  8. }
  9.  
  10. class Ksiega {
  11. protected $wpisy = array();
  12.  
  13. public function pobierz_wpisy() {
  14. // Zapytanie do bazy
  15.  
  16. foreach ($wpisy_z_bazy as $wpis_jako_tablica) {
  17. $wpis = new Wpis($wpis_jako_tablica['data'], $wpis_jako_tablica['tresc']);
  18.  
  19. $this->wpisy[] = $wpis;
  20. }
  21. }
  22.  
  23. public function dodaj_wpis(Wpis $wpis) {
  24. $wpis->dodaj();
  25. }
  26. }
thek
Zagiewa... Popatrz na to tak jak phpion czy ja. Najbardziej elementarny jest wpis i to on zawiera wszystkie wymienione pola. Nazwijmy więc klasę tak, jak naprawdę ona się przedstawia - Wpis. Dopiero wpisy tworzą pewien zbiór, kolekcję, którą nazywamy księgą wpisów. Skoro tak, to klasa Ksiega_wpisow może być implementowana jako tablica obiektów typu Wpis. Jak to by wyglądało w kodzie? tak naprawdę to tylko tak, że jedyną potrzebną klasą byłby Wpis a księga to byłaby zwyczajna tablica i przez to naturalne byłoby działanie w stylu.
$ksiega_wpisow[] = new Wpis;
Można tworzyć dodatkową klasę, która by się zajmowała szerszą grupą wpisów, ale bazowo tak naprawdę potrzeba Ci:
klasa Wpis
Pola: imie, email, strona, gg, wpis, dodano (pole w bazie z ustawionym CURRENT_TIMESTAMP)
Metody: dodaj, edytuj (tak naprawdę dodaj i edytuj można ująć jedną metoda wykorzystując ON DUPLICATE UPDATE), usun, pokaz(zwraca pojedynczy wpis)

Klasa Księga tak naprawdę nie byłaby czymś innym niż:
klasa Ksiega
Pola: lista_wpisow (zwykła tablica przechowująca obiekty klasy Wpis)
Metody: pokaz(zwraca listę iluś wpisów według określonego wzorca wyszukiwania), ewentualne kombinowanie z dodaniem, edycją lub usuwaniem wielu na raz to tak naprawdę to samo co posiada klasa wpis. Duplikowalibyśmy więc metody klasy Wpis lub w skrócie moglibyśmy napisać je jako wywołanie metody obiektu Wpis wielokrotnie.
Mikz
Cytat(phpion @ 28.06.2010, 12:20:29 ) *
Chyba nie do końca wiesz o czym piszesz.

Zrozumiałem że proponujesz żeby księga była obiektem. Ja bym raczej skłaniał się ku utworzeniu klasy z polami i metodami statycznymi. Wtedy struktura tworzy nam się całkiem sensowna, mamy zbiór metod które zarządzają wszystkimi wpisami, które, tak jak zaproponowałeś, znajdują się w tablicy. Chyba że mówiłeś o czym innym, wtedy zwracam honor.

Edit: Zresztą Twój następny post potwierdza moje przypuszczenie, przy utworzeniu klasy ze statycznymi metodami nie ma potrzeby tworzyć nowej instancji obiektu Ksiega, tylko odwołujemy się tak:

Ksiega::pobierz_wpisy();

lub

Ksiega::dodaj_wpis($wpis);

Więc jeżeli nie mamy na stronie więcej niż jednej księgi lub nie tworzymy jakiejś złożonej biblioteki, wydaje mi się że takie rozwiązanie jest lepsze.
tmka
Witam,
ja jeszcze wtrącę się na temat twojego kodu Zagiewa. Pytałeś się czemu u siebie użyłem oddzielnych metod ustawiających i pobierających (setterów i getterów potocznie mówiąc) dla każdego z pól. Dzięki takiemu rozwiązaniu możesz np. zwalidować przesłane dane zanim je zapiszesz do pola obiektu. Oczywiście, możesz to również zrobić w metodzie takiej jak twoja, ale jeżeli pól będzie dużo, to metoda rozrośnie się i będzie mało elegancka. Dodatkowo, gdy zechcesz rozbudować obiekt o dodatkowe pola, bedziesz musiał modyfikować tą metodę, a w obiektówce takie działanie jest niepożądane, bo np. mogłeś już użyć tej metody w wielu miejscach i przy zmianie ilości argumentów będzie trzeba albo poustawiać je w deklaracji metody na jakieś domyślne wartości, albo poprostu modyfikować każde wywołanie. Bardziej eleganckim sposobem jest właśnie zrobienie getterów i setterów, nawet jeżeli pol jest niewiele, poprostu dobrze już mieć taki nawyk.

Jeszcze podam takie małe 'ułatwienie' w pisaniu setterow. Otóż w php można zrobić coś takiego:
  1. public setDzien($dzien)
  2. {
  3. $this->_dzien = $dzien;
  4. return $this; //zwracamy instancje do 'siebie',
  5. }
  6.  
  7. public setMiesiac($mies)
  8. {
  9. $this->_mies= $mies;
  10. return $this; //zwracamy instancje do 'siebie',
  11. }
  12.  
  13. //normalnie ustawienie wyglądałoby tak:
  14. $data = new Data();
  15. $data->setDzien(12);
  16. $data->setMiesiac(4);
  17.  
  18. //przy konstrukcji metod ustawiających które zwracaja instancje do swojego obiektu
  19. //bedzie wygladac to tak:
  20. $data->setDzien(12)->setMiesiac(4);
  21.  
  22.  


Może dodam jeszcze słowo wyjaśnienia. Gdy wywolasz któregoś z setterów, zostanie zwrócony obiekt dla którego ta metoda została wywołana, następnie możesz 'w locie' wywołać kolejną metode tego obiektu itd. wystarczy zeby metoda zwracala obiekt do ktorego należy, czyli poprostu $this.

Zagiewa
Wiem, że już trochę minęło od dnia kiedy założyłem ten temat ale nie miałem czasu sad.gif Przerobiłem moją klasę według waszych wskazówek i na chwile obecną wygląda ona tak:
  1. <?php
  2.  
  3. class wpis {
  4.  
  5. private $_data = null;
  6. private $_godzina = null;
  7. private $_imie = null;
  8. private $_email = null;
  9. private $_strona = null;
  10. private $_gg = null;
  11. private $_wpis = null;
  12.  
  13. public function ustaw_wartosci($data, $godzina, $imie, $email, $strona, $gg, $wpis) {
  14.  
  15. $this->_data = $data;
  16. $this->_godzina = $godzina;
  17. $this->_imie = $imie;
  18. $this->_email = $email;
  19. $this->_strona = $strona;
  20. $this->_gg = $gg;
  21. $this->_wpis = $wpis;
  22. }
  23.  
  24. public function save() {
  25.  
  26. include('dane.php');
  27. $sql = mysql_connect(SQL_HOST, SQL_USER, SQL_PASS) or
  28. die("Sprawdź połączenie z serwerem! " . mysql_error());
  29.  
  30. mysql_select_db(SQL_DB, $sql) or
  31. die("Sprawdź bazę! " . mysql_error());
  32.  
  33. $insert = "INSERT INTO wpisy (data, godzina, imie, email, strona, gg, wpis)
  34. VALUES ('$this->_data', '$this->_godzina', '$this->_imie', '$this->_email', '$this->_strona', '$this->_gg', '$this->_wpis')";
  35.  
  36. $result = mysql_query($insert) or
  37. die('Dodanie wpisu nie powiodło się. ' . mysql_error());
  38. }
  39. }
  40.  
  41. class ksiega {
  42.  
  43. protected $wpisy = array();
  44.  
  45. public function pokaz() {
  46.  
  47. return $this->_data.'\n';
  48. return $this->_godzina.'\n';
  49. return $this->_imie.'\n';
  50. return $this->_email.'\n';
  51. return $this->_strona.'\n';
  52. return $this->_gg.'\n';
  53. return $this->_wpis.'\n';
  54. }
  55.  
  56. public function load_all() {
  57.  
  58. include('dane.php');
  59. $sql = mysql_connect(SQL_HOST, SQL_USER, SQL_PASS) or
  60. die("Sprawdź połączenie z serwerem! " . mysql_error());
  61.  
  62. mysql_select_db(SQL_DB, $sql) or
  63. die("Sprawdź bazę! " . mysql_error());
  64.  
  65. $select = "SELECT * FROM wpisy ORDER BY id DESC ";
  66. $result = mysql_query($select) or
  67. die('Załadowanie wpisów z bazy nie powiodło się. ' . mysql_error());
  68. }
  69. }
  70. ?>

Jestem wręcz pewien, że można to zrobić lepiej niż obecnie to wygląda więc prosił bym o dalsze wskazówki jak to polepszyć. smile.gif
cojack
Zainteresuj się wzorcem GenericObject oraz GenericObjectCollection i znajdziesz odpowiedź na swoje pytanie. Przy okazji wzorzec fabryki do wykorzystania różnych silników baz danych, słowa kluczowe to: GenericObject, GenericObjectCollection, DatabaseConnection, DatatabaseQuery, DatabaseTransaction, ExceptionFactory
Crozin
1) Metody z serii "ustawi 123123123 wartości na raz" są bez sensu.
2) Nie da się na raz zwrócić 10 wartości (ksiega::pokaz())
3) Nie uważasz za bezsensowne każdorazowe łączenie się z bazą danych w metodach save()?
4) Data/godzina - do tego nie potrzeba dwóch zmiennych - jedna jest w pełni wystarczająca
everth
Swoją drogą to najlepiej te wszystkie zawiłości opanujesz ucząc się innego języka niż PHP (np. C++). Później nauka większości języków oprogramowania jest bardziej sprawna. Co do twojej klasy to od razu da się zastosować tutaj dziedziczenie np. z ArrayObject PHP (do klasy Księga - de facto jest to kolekcja wpisów, ArrayObject fajnie nadaje się do tworzenia kolekcji) czyli łopatologicznie:
  1. <?php
  2.  
  3. // Deklaracja klas, dobrym zwyczajem jest umieszczanie każdej klasy w oddzielnym pliku,
  4. // ja robię tak że jeśli są powiązane i małe to wrzucam je do jednego (np. klasa Ksiega z klasą wpis, klasa MyPDO z klasą SqlObject itd.)
  5.  
  6. class MyPDO extends PDO { //dopisujemy parę funkcji do bazodanowej klasy PDO
  7. public function insert(SqlObject $insert) {
  8. return parent::prepare($insert->insertSqlCode());
  9. }
  10.  
  11. public function remove(SqlObject $remove) {
  12. return parent::prepare($remove->removeSqlCode());
  13. }
  14. }
  15.  
  16. abstract class SqlObject { //abstract oznacza że klasa nie może być samodzielnym obiektem, służy jako szablon po którym mogą dziedziczyć inne klasy
  17. public $table_name = get_class($this); // domyślnie nazwa klasy jest nazwą tabeli, pokraczne rozwiązanie ale nie chce mi się mysleć
  18.  
  19. public function insertSqlCode() {
  20. $data = $this->prepareData();
  21. $insert = "INSERT INTO ".$this->table_name." (".implode(',',array_keys($data)).") VALUES (".implode(',',$data).")";
  22. return $insert;
  23. }
  24.  
  25. public function removeSqlCode() {
  26. $data = $this->prepareData();
  27. $remove = "DELETE FROM ".$this->table_name." WHERE ";
  28.  
  29. // normalnie przefiltrowalibysmy rekordy do usunięcia po kluczu ale klasa Wpis takowego nie ma, filtrujemy wiec po wszystkich polach (naprawde pokraczne)
  30. $filters = array();
  31. foreach($data as $name=>$value) {
  32. $filters[] = $this->table_name.".".$name."='".$value."'";
  33. }
  34. $remove .= implode(' AND ',$filters);
  35.  
  36. return $remove;
  37. }
  38.  
  39. protected function prepareData() { //przygotuj dane z pól obiektu, wykluczając zbyteczne
  40. $data = get_vars_object($this); //pobieramy dane obiektu
  41. unset($data['table_name']); //usuwamy pole z nazwą tabeli
  42. return $data
  43. }
  44. }
  45.  
  46. class Wpis extends SqlObject {
  47.  
  48. public $table_name = "Ksiega"; // nadpisujemy domyślną nazwę tabeli
  49.  
  50. protected $_data = null;
  51. protected $_godzina = null;
  52. protected $_imie = null;
  53. protected $_email = null;
  54. protected $_strona = null;
  55. protected $_gg = null;
  56. protected $_wpis = null;
  57.  
  58. public function __construct($data, $godzina, $imie, $email, $strona, $gg, $wpis) {
  59.  
  60. $this->_data = $data;
  61. $this->_godzina = $godzina;
  62. $this->_imie = $imie;
  63. $this->_email = $email;
  64. $this->_strona = $strona;
  65. $this->_gg = $gg;
  66. $this->_wpis = $wpis;
  67. }
  68.  
  69. public function showHtmlTableRow() {
  70. $resultString = "<tr>";
  71. $data = $this->prepareData() //nieładnie zrobione ale działa ;)
  72. foreach($data as $name=>$value) {
  73. $resultString .= "<td class=".$name.">".$value."</td>";
  74. }
  75. $resultString .= "</tr>";
  76. return $resultString;
  77. }
  78.  
  79. }
  80.  
  81. class Ksiega extends ArrayObject {
  82. public $db;
  83. public $table_name = 'Ksiega'; // kolejna pokraka
  84.  
  85. public function __construct($db) {
  86. $this->db = $db; // ponieważ moja klasa PDO nie jest singletonem to przekazuję ją jako referencję
  87. }
  88.  
  89. function offsetset($index=null, Wpis $value) { //nadpisujemy domyślną metodę klasy ArrayObject
  90. $this->db->insert($value)->execute(); //dodając wpis do kontenera automatycznie dodajemy go do bazy
  91. parent::offsetset($index, $value);
  92. }
  93.  
  94. function offsetUnset($index) { //przy usuwaniu wpisu z Ksiegi usuwaj tez wpis z bazy
  95. $wpis = $this[$index];
  96. if ($wpis) $this->db->remove($wpis)->execute();
  97. $wpis = NULL; //nie wiem czy to potrzebne ale dla świętego spokoju lepiej zniszczyć obiekt który nie ma odniesienia w bazie
  98. parent::offsetUnset($index);
  99. }
  100.  
  101. public function retrieveEntriesFromDB() {
  102. $sth = $this->db->prepare("SELECT * FROM ".$this->table_name);
  103. $sth->setFetchMode(PDO::FETCH_CLASS, 'Wpis'); // zamiast pobierać rekordy jako tablice, tworzymy z nich obiekty klasy Wpis
  104. $sth->execute();
  105. foreach ($sth as $wpis) {
  106. $this[] = $wpis; //dodaje kazdy rekord jako obiekt Wpis do kontenera Ksiega
  107. }
  108. }
  109.  
  110. public function showEntriesAsHtmlTable() {
  111. $resultString = "<table>";
  112. foreach ($this as $entry) {
  113. $resultString .= $entry->showHtmlTableRow();
  114. }
  115. $resultString .= "</table>";
  116. return $resultString;
  117. }
  118. }
  119.  
  120.  
  121. // WYKONANIE SKRYPTU
  122.  
  123. $db = new MyPDO($moja_konfiguracja_bazy);
  124.  
  125. $ksiega = new Ksiega($db);
  126. $ksiega->retrieveEntriesFromDB();
  127. echo $ksiega->showEntriesAsHtmlTable();
  128.  
  129. $wpis = new Wpis(date(),time(),'Jasiu','fasola@email.com','abojawiem',32167,'Nowy wpis');
  130.  
  131. $ksiega[] = $wpis // dodajemy wpis do bazy,oraz do kontenera Ksiega, ew. trzeba zastosować "REPLACE" zamiast "INSERT" żeby uniknac dublowania rekordów
  132.  
  133. unset($ksiega[5]); // usuwamy z Ksiegi i bazy wpis numer 5
  134.  
  135.  
  136. ?>

Nie parsowałem powyższego skryptu więc nie wiem czy zadziała. W każdym razie jak zapoznasz się z OOP to zobaczysz że nie da się normalnie pisać w PHP bez niego (ja przynajmniej nie potrafię smile.gif). Ale jak naprawdę chcesz być dobry to weź inny język programowania np. C++ lub Javę i tam spróbuj coś napisać. Jak tam dojdziesz do przyzwoitego poziomu to PHP będzie bułką z masłem. Po prostu PHP uczy złych nawyków.

BTW, wcześniej ktoś wspomniał o możliwych wyciekach pamięci w skryptach PHP. Może ja czegoś nie wiem lub nie rozumiem, ale przecież to chyba niemożliwe skoro pamięć jest zwalniana po zakończeniu działania programu. A PHP kończy się wykonywać wraz z końcem skryptu - czyli tak: CGI wywołuje interpreter PHP jako proces - PHP alokuje standardowy rozmiar pamięci, parsuje skrypt i rozpoczyna jego wykonanie, wszelkie wycieki pamięci powstają w obrębie za-alokowanej pamięci (od tego mamy Garbage Collectora), skrypt kończy działanie, PHP zwraca wynik i kończy swoje działanie - pamięć przez niego zajęta jest oznaczana jako wolna. Tak więc skrypt musi być naprawdę kompleksowy i rozbudowany żeby wycieki pamięci mogły odgrywać znaczącą rolę. Dziwię się bo jeszcze nigdy się z problemem wycieku pamięci w PHP nie spotkałem (ani też nie stosowałem destruktorów bez potrzeby).
thomson89
Ja piszę obiektowo już od 6 miesięcy. Zacząłem gdy zacząłem pisać sklep internetowy. Powiem, że w tej chwili bez obiektowego pisania dużo bym nie zrobił. Jak dotąd, z łatwością mi się pisało wszystkie klasy. Tworzę nie jednokrotnie pliki które mają 700 linijek kodu.

Ja dzięki obiektowemu pisaniu aplikacji, przede wszystkim ułatwiłem sobie edycję. Mam przykładowo klasę produkt i plik produkty. W klasie produkt piszę wszystko co potrzebne, czyli np. dodaj, zmien, usun, sprawdz. A w pliku produkty tylko pobieram dane z formularza i:
  1. require_once('klasy/produkt.class.php');
  2. $produkt = new produkt;
  3. $produkt -> dodaj($_POST);


I tyle. W razie jakiś dodatkowych pól, lub innych tego typu po prostu edytuję JEDEN PLIK! A nie jak w strukturalnym plik z formularzem, plik odbierający i plik umieszczający. Przy dużych projektach jest to naprawdę obowiązkowe pisanie aplikacji.
Pilsener
A ja jeszcze dodam, że pisząc obiektowo dostajemy cały "arsenał" narzędzi wspomagających programowanie, od bibliotek, pluginów, dodatków i frameworków zaczynając, a kończąc na prawdziwych kombajnach, gdzie mamy pod ręką zmienne lokalne i globalne, podpowiedzi (typu np. lista dostępnych metod danego obiektu wraz z opisem), przeglądarkę obiektów - można stworzyć prostą aplikacyjkę bez pisania nawet linijki kodu.
cojack
IDE jakieś sobie zainstalowałeś? Czu przesiadłeś się na ASPX?
Luneth
Cytat(Crozin @ 23.07.2010, 23:30:50 ) *
1) Metody z serii "ustawi 123123123 wartości na raz" są bez sensu.
2) Nie da się na raz zwrócić 10 wartości (ksiega::pokaz())
3) Nie uważasz za bezsensowne każdorazowe łączenie się z bazą danych w metodach save()?
4) Data/godzina - do tego nie potrzeba dwóch zmiennych - jedna jest w pełni wystarczająca


Wszystkie wypowiedzi poza pierwszą linijką są oczywiste, ale myślę, że autor (tak samo jak i ja) chętnie dowiedziałby się co konkretnie miałeś na myśli, czy porobienie settera dla każdego pola, a może ustawienie ich jako publiczne, lub jeszcze jakieś inne rozwiązanie? smile.gif
everth
To zależy. Settery ułatwiają pracę gdyby trzeba zmieniać kod - wtedy metoda settera zostaje, ale sam setter może dowolnie przekształcać dane. Ale ponieważ PHP nie jest językiem kompilowanym to trzeba zachować umiar - settery do każdej głupoty (gdzie wystarcza public) mają narzut na wydajność. Po prostu musisz się zdecydować czy dana zmienna może kiedyś potrzebować dodatkowej obróbki, czy też nie.
phpion
@everth:
Ja nigdy nie korzystam z publicznych składowych klasy. Wszystkie składowe mają swoje gettery i settery. Dlaczego? Mam wówczas pełną kontrolę nad tym, co siedzi w obiekcie. Nawet takie prozaiczne ustawianie imienia robię setterem rzutując przekazywaną wartość na string.
  1. public function set_name($name) {
  2. $this->name = (string)$name;
  3. }

Fakt - jest to czasem upierdliwe bo zanim przejdę do pisania kodu klasy to wcześniej muszę napisać wszystkie settery i gettery (wraz z phpDoc'em). Mam jednak tego pecha, że jestem strasznie pedantyczny pod kątem kodu i wszystko musi być na tip-top winksmiley.jpg.
Crozin
@phpion: settery/gettery można z automatu generować przez IDE winksmiley.jpg

Co do bezsensowności czegoś takiego (tj. ustawiania wszystkiego przez jedną metodę).
1) Co jeżeli masz już obiekt i chcesz zmienić jedną składową?
2) Zapamiętanie kolejności 10 parametrów to zbędny wysiłek
3) Burdel w kodzie (w momencie gdy chcesz zrobić coś więcej niż tylko przypisać w metodzie wartości argumentów do składowych)
4) Utrudniona dokumentacja
5) Utrudniona rozbudowa kodu (chcąc dodać nową składową musisz w metodzie ustaw wstawić ją na końcu jako opcjonalny argument - inaczej tracisz wsteczną kompatybilność)
Luneth
Crozin, chodziło mi nie tyle o uzasadnienie co zaproponowanie lepszego rozwiązania winksmiley.jpg
everth
Fakt - ale czasem ustawia się podstawowe właściwości obiektu poprzez konstruktor i ja nie widzę w tym nic złego (jest to nawet czytelniejsze niż 10 wywołań jedno pod drugim) - choć ja wolę przekazywać to za pomocą tablicy a nie zmiennych (gdzieś ktoś napisał że jak funkcja ma więcej niż 2 argumenty to jest do dupy).
Crozin
@everth: w konstruktorze podaje się wyłącznie argument wymagane do tego by w ogóle dało się utworzyć obiekt. A ta teza, że metoda z więcej niż dwoma argumentami jest do dupy... jest do dupy.
phpion
@Crozin:
Netbeans posiada generatory setterów/getterów, Eclipse PDT niestety nie (chyba, że nie potrafię tego znaleźć).

@everth:
Jeśli przesyłasz parametry na hura w postaci tablicy to możesz sobie darować podpowiadanie parametrów w IDE. Podpowiedź, że możesz podać tablicę niewiele da. Osobiście wolę jawnie znać nazwy, znaczenie oraz typy poszczególnych parametrów (szczególnie przy przekazywaniu obiektów).
everth
Cytat(Crozin @ 26.07.2010, 15:22:23 ) *
@everth: w konstruktorze podaje się wyłącznie argument wymagane do tego by w ogóle dało się utworzyć obiekt. A ta teza, że metoda z więcej niż dwoma argumentami jest do dupy... jest do dupy.

I tak i nie. Może przez pewne naleciałości z C++ wiem jak cholernie trudno było tropić błędy w funkcjach przyjmujących po 5 i 6 argumentów, nie tędy droga. Dla mnie metoda przyjmuje coś -> przekształca coś, ew. korzystając z właściwości obiektu -> i ew. zwraca coś. Złota zasada - jedna funkcja robi jedną rzecz, dodatkowe argumenty z reguły służą modyfikacji działania funkcji czyli zaprzeczają powyższej zasadzie.
Skoro akceptujesz sytuację z pierdyliardem setterów/getterów to powiedz mi czy dlaczego setter nie może przyjmować więcej niż jedne argument? Przecież setter może być zbudowany tak że przyjmuje argument bazowy oraz zmienne modyfikujące.

Cytat(phpion @ 26.07.2010, 16:01:36 ) *
@everth:
Jeśli przesyłasz parametry na hura w postaci tablicy to możesz sobie darować podpowiadanie parametrów w IDE. Podpowiedź, że możesz podać tablicę niewiele da. Osobiście wolę jawnie znać nazwy, znaczenie oraz typy poszczególnych parametrów (szczególnie przy przekazywaniu obiektów).

Mogę sobie na to pozwolić jeśli ograniczam się do pól które w moim obiekcie i tak są public. Czyli według zasady - nazwa pola => wartość. To i tak łatwiejsze do modyfikacji niż ciąg argumentów.
phpion
Cytat(everth @ 26.07.2010, 16:28:32 ) *
Złota zasada - jedna funkcja robi jedną rzecz, dodatkowe argumenty z reguły służą modyfikacji działania funkcji czyli zaprzeczają powyższej zasadzie.

Zgadza się - jedna funkcja robi jedną rzecz. Ale zauważ, że często przydatne są funkcje "skrótowe", które przyjmą np. 3 parametry i wywołają odpowiednie metody atomowe. Prosty przykład:
  1. class Page {
  2. public function render(Page_Header $header, Page_Body $body, Page_Footer $footer) {
  3. $this->render_header($header);
  4. $this->render_body($body);
  5. $this->render_footer($footer);
  6. }
  7.  
  8. public function render_header(Page_Header $header) {
  9. //
  10. }
  11.  
  12. public function render_body(Page_Body $body) {
  13. //
  14. }
  15.  
  16. public function render_footer(Page_Footer $footer) {
  17. //
  18. }
  19. }

Czy wg Ciebie przekazanie 3 parametrów do metody render() jest błędne?

Cytat(everth @ 26.07.2010, 16:28:32 ) *
Skoro akceptujesz sytuację z pierdyliardem setterów/getterów to powiedz mi czy dlaczego setter nie może przyjmować więcej niż jedne argument? Przecież setter może być zbudowany tak że przyjmuje argument bazowy oraz zmienne modyfikujące.

Zadaniem settera jest ustawianie wartości składowej obiektu. Skąd więc pomysł by przekazywać do niego X parametrów? Przekazujesz 1 parametr, który jest wartością, która będzie przypisana do składowej.

Cytat(everth @ 26.07.2010, 16:28:32 ) *
Mogę sobie na to pozwolić jeśli ograniczam się do pól które w moim obiekcie i tak są public. Czyli według zasady - nazwa pola => wartość. To i tak łatwiejsze do modyfikacji niż ciąg argumentów.

Już lepszym rozwiązaniem byłoby (zamiast jawnego $this->$var = $value) wywoływać call_user_func(array($this, 'set_'.$var), $value). Wtedy wszystkie ustawienia wartości lecą przez odpowiednie settery.
darko
Cytat(haahh @ 24.06.2010, 21:10:54 ) *
Strukturalny faktycznie strasznie się edytuję. Sam zmieniałem ostatnio strukturę wyświetlania mojego "małego portalu" php i to była masakra. Muszę przejść na obiektowy styl pisania kodu - ktoś poleci jakieś książki traktujące o średnio-zaawansowanym php i pisanie obiektowym?

Polecam, tania i warta swej ceny, ale raczej dla średnio-zaawansowanych i zaawansowanych.
everth
Cytat(phpion @ 27.07.2010, 08:13:54 ) *
Zgadza się - jedna funkcja robi jedną rzecz. Ale zauważ, że często przydatne są funkcje "skrótowe", które przyjmą np. 3 parametry i wywołają odpowiednie metody atomowe. Prosty przykład:
  1. class Page {
  2. public function render(Page_Header $header, Page_Body $body, Page_Footer $footer) {
  3. $this->render_header($header);
  4. $this->render_body($body);
  5. $this->render_footer($footer);
  6. }
  7.  
  8. public function render_header(Page_Header $header) {
  9. //
  10. }
  11.  
  12. public function render_body(Page_Body $body) {
  13. //
  14. }
  15.  
  16. public function render_footer(Page_Footer $footer) {
  17. //
  18. }
  19. }

Czy wg Ciebie przekazanie 3 parametrów do metody render() jest błędne?


Zadaniem settera jest ustawianie wartości składowej obiektu. Skąd więc pomysł by przekazywać do niego X parametrów? Przekazujesz 1 parametr, który jest wartością, która będzie przypisana do składowej.


Już lepszym rozwiązaniem byłoby (zamiast jawnego $this->$var = $value) wywoływać call_user_func(array($this, 'set_'.$var), $value). Wtedy wszystkie ustawienia wartości lecą przez odpowiednie settery.

Moim zdaniem jest błędne bo według mnie metoda render powinna być funkcją (void). A parametry powinny być właściwościami klasy Page. Albo inaczej powinna istnieć klasa RenderEngine mająca metodę render która przyjmuje obiekty page lub body lub footer (powinny dziedziczyć po jakimś abstrakcie). Tak mi się wydaje. Ale ponieważ jestem pragmatykiem to akceptuję to jeśli pracuję na czyimś kodzie (nie będę przerabiał całego kodu).

Przykład z setterami jest naciągany. Call_user_func dla mnie ma ograniczone zastosowanie - to taka szybsza wersja eval, a to odstręcza mnie zawsze od stosowania w kodzie (bo wolna, bo trudna w debugowaniu, bo może dawać nieprzewidziane rezultaty, bo może powodować dziury w bezpieczeństwie, bo...). Tak więc to co piszesz, choćby ze względu na wydajność (pomijając czytelność) dla mnie jest wykluczone.
Crozin
call_user_func i inne/zmienne zmiennych - to nie szybsza wersja evala tylko RefelctionAPI. Co do wolności ich wykonywania to się nie zgadzam - natomiast fakt, faktem debuggowanie utrudniają.

Przykład metody, która wymaga wielu parametrów: ot chociażby metoda rysująca prostopadłościan (x, y, z, width, height, depth) - oczywiście można by to zastąpić dwoma obiektami (Point3D(x, y, z), Cuboid(width, height, depth)) ale takie coś można by podciągnąć chyba pod wszystko. Nie mniej jednak przykład nie przyszedł mi od razu do głowy - bo takich metod się nie stosuje zazwyczaj. Jednak czasami się tak zdarza, że coś potrzebuje tych kilku argumentów - wtedy trzeba zadbać o to by było to maksymalnie logiczne i dobrze udokumentowane.
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.