Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [Klasy]Budowanie klas i użycie konstruktora
Forum PHP.pl > Forum > PHP > Object-oriented programming
PawelC
Hej smile.gif
Jakiś czas temu, zamówiłem książkę o OOP, trochę poczytałem i zacząłem praktykę. Stworzyłem sobie klasę mail która wysyła maila, i użyłem w niej konstruktora, i chciałem się dowiedzieć, czy dobrze myślę odnośnie tworzenia klas i użycia konstruktora w nich. Oto kod:
  1. <?php
  2.        class mail
  3.        {
  4.            public $nadawca;
  5.            public $odbiorca;
  6.            public $temat;
  7.            public $tresc;
  8.            
  9.            
  10.                    function __construct($odbiorca)
  11.                    {
  12.                        $this -> odbiorca = $odbiorca;
  13.                    }
  14.                    
  15.                    
  16.                    public function ustawTemat($temat)
  17.                    {
  18.                        $this-> temat = $temat;
  19.                    }
  20.                    
  21.                    
  22.                    public function ustawTresc($tresc)
  23.                    {
  24.                        $this -> tresc= $tresc;
  25.                    }
  26.                    
  27.                    
  28.                    public function ustawNadawce($nadawca)
  29.                    {
  30.                        $this-> nadawca = $nadawca;
  31.                    }
  32.                    
  33.                    
  34.                    public function wyslijMaila()
  35.                    {
  36.                        mail($this->odbiorca,$this->temat,$this->tresc.$this->nadawca);
  37.                    }
  38.        }
  39.        
  40. $mail=new mail('adres@wp.pl');
  41. $mail->ustawNadawce('ktos@adres.pl');
  42. $mail->ustawTemat('Temat testowy');
  43. $mail->ustawTresc('przykladowa tresc');
  44. $mail->wyslijMaila();
  45. ?>

Proszę o opinie, w szczególności czy mój tok rozumowania odnośnie tworzenia klas i używania w nich konstruktora jest dobry. Wiem że dla Was, napisanie takiej klasy to pikuś, ale dopiero raczkuje w OOP i chciałbym poznać waszą opinię.
LBO
@belliash: nie musi.

@ExPlOiT: całkiem zgrabnie jak na początek, ale kilka uwag się znajdzie.
Po pierwsze, może być kilku odbiorców, a ty tego nie wziąłeś pod uwagę.

Po drugie mógłbyś wydzielić wysyłanie maila np. do osobnej klasy lub poprzez dziedziczenie.
  1. <?php
  2. // wysylanie maila w osobnej klasie
  3. class mail
  4. {
  5.    protected $sender;
  6.  
  7.    public __construct(mailSender $sender)
  8.    {
  9.        $this->sender = $sender;
  10.    }
  11.  
  12.    // tutaj reszta Twoich metod + ustawNadawce/Nadawcow
  13.  
  14.    public function wyslijMaila()
  15.    {
  16.        // teraz mozesz tworzyc klase dziedziczaca po mailSender
  17.        // i wewnatrz niej użyć mail lub inną w której sam będziesz składać nagłowki do kupy
  18.        // i wysylac do serwera poczty.
  19.        $this->sender->send($this->odbiorca,$this->temat,$this->tresc.$this->nadawca);
  20.    }
  21. }
  22. ?>


Wiem, że na początek to dużo po wprowadzam rzeczy z którymi niekoniecznie jesteś zaznajomiony, ale w ten sposób od początku nauczysz się dobrych praktyk.
piotrooo89
a ja to rozwiązałem tak:

Temat: klasa_mailing

tylko wydaje mi się że trochę nie o to chodzi bo ty na sztywno podajesz maile a ja je dynamicznie wczytuje.
LBO
Cytat(belliash @ 19.04.2009, 23:07:28 ) *
@LBO: wiem ze nie musi - domyslnie przyjmowane jest jako public... ale jak pisac to pisac wszedzie albo nigdzie. winksmiley.jpg


Ale to już kwestia standardów kodowania a nie poprawnej konstrukcji klasy.

Cytat(piotrooo89 @ 19.04.2009, 23:09:54 ) *
tylko wydaje mi się że trochę nie o to chodzi bo ty na sztywno podajesz maile a ja je dynamicznie wczytuje.


Mailing (wysyłka do subskrybentów) )a mailer (mechanizm wysyłania maila) to dwie rożne rzeczy i nie powinieneś Ich mieszać. Skłaniałbym się do wykorzystania obiektów mail wewnątrz klasy mailera.
PawelC
Dzięki za uwagi. Ta klasa ma obsłużyć wysyłanie do mnie maila z formularza kontaktowego, czyli będzie jeden odbiorca. Bo w przypadku gdyby było kilku odbiorców mógłbym to tak zrobić:
  1. <?php
  2.        class mail
  3.        {
  4.            public $nadawca;
  5.            public $odbiorca;
  6.            public $temat;
  7.            public $tresc;
  8.            
  9.            
  10.                    function __construct($nadawca)
  11.                    {
  12.                        $this -> nadawca = $nadawca;
  13.                        $this -> odbiorca = array();
  14.                    }
  15.                    
  16.                    
  17.                    public function ustawTemat($temat)
  18.                    {
  19.                        $this-> temat = $temat;
  20.                    }
  21.                    
  22.                    
  23.                    public function ustawTresc($tresc)
  24.                    {
  25.                        $this -> tresc= $tresc;
  26.                    }
  27.                    
  28.                    
  29.                    public function dodajOdbiorce($odbiorca)
  30.                    {
  31.                        array_push($this->odbiorca,$odbiorca);
  32.                    }
  33.                    
  34.                    
  35.                    public function wyslijMaila()
  36.                    {
  37.                        
  38.                        foreach($this->odbiorca as $dokogo)
  39.                        {
  40.                        mail($dokogo,$this -> temat,$this->tresc,'From:'. $this->nadawca);
  41.                        }
  42.                    }
  43.        }
  44.        
  45. $mail=new mail('nadawca@wp.pl');
  46. $mail->dodajOdbiorce('biuro@cos.pl');
  47. $mail->ustawTemat('Temat testowy');
  48. $mail->ustawTresc('przykladowa tresc');
  49. $mail->wyslijMaila();
  50. ?>

Oczywiście o ile dobrze myślę. I np w wczytać listę odbiorców z pliku txt
Crozin
Rada: jak najszybciej porzuć polskie nazewnictwo w kodzie

@LBO: Jak rozumiem chciałeś pokazać możliwość uzyskania kilku dróg wysłania maila, przez: mail(), smtp, cokolwiek innego. Tylko wtedy klasa MailSender nie może dziedziczyć po Mail - to by bez sensu było przecież. winksmiley.jpg Powinna za to przyjmować cały obiekt Mail jako jakiś argument (w końcu z czasem klasa Mail rozrośnie się o dołączanie załączników itp. więc przekazywanie poszczególnych pól danych nie spisze się za dobrze).

  1. <?php
  2.  
  3. class Mail{
  4.    private $addressee = array();
  5.    private $sender;
  6.    
  7.    private $subject;
  8.    private $content;
  9.    
  10.    public function __construct(){
  11.        //w konstruktowrze nie ma sensu niczego upychać na siłę
  12.        //możesz co prawda dodać obsługę nadawania nadawcy
  13.    }
  14.    
  15.    public function addAddressee($mail, $name){
  16.        //mail to adres, name to ładna nazwa trafiająca do nagłówka
  17.        $this->addressee[$mail] = $name;
  18.    }
  19.    
  20.    public function setSender($sender){
  21.        $this->seneder = $sender;
  22.    }
  23.    
  24.    public fuction setSubject($subject){
  25.        $this->subject = $subject;
  26.    }
  27.    
  28.    public function setContent($content){
  29.        $this->content = $content;
  30.    }
  31. }
  32.  
  33. abstract class MailSender{
  34.    private $mail;
  35.  
  36.    public function setMail(Mail $mail){
  37.        $this->mail = $mail;
  38.    }
  39.    
  40.    abstract public function send();
  41. }
  42.  
  43. class SMTPMailSender extends MailSender{
  44.    public function send(){
  45.        //wysyłanie maila poprzez SMTP
  46.    }
  47. }
  48.  
  49. class MailMailSender extends MailSender{
  50.    public function send(){
  51.        //wysyłanie maila poprzez mail()
  52.    }
  53. }
  54.  
  55. //--------------------------
  56. $mail = new Mail();
  57. //ustawienie wszystkich danych
  58. $sender = new MailMailSender();
  59. $sender->setMail($mail);
  60. $sender->send();
  61.  
  62.  
  63. //--------------------------
  64. //ewentalnie możesz w Mail dodać metodę robiącą to co powyżej
  65. ?>
Oczywiście to tylko szkielet z najbardziej podstawowymi metodami. Zauważ że taka konstrukcja umożliwia Ci masowe wysyłanie dwóch rodzajów maili:
1) Wielu adresatów, jedna treść: wtedy tworzysz jeden Mail, jeden MailSender a wielu adresatów obsługujesz poprzez podanie wielu maili w pierwszym parametrze mail() (więcej w manualu)
2) Wielu adresatów, dla każdego inna treść: wtedy tworzysz kilka obiektów Mail i poprzez MailSeneder::addMail() (tutaj nie pokazanej) wielokrotnie (w pętli) wykonujesz całe wysyłanie
LBO
Cytat(Crozin @ 20.04.2009, 08:11:01 ) *
@LBO: Jak rozumiem chciałeś pokazać możliwość uzyskania kilku dróg wysłania maila, przez: mail(), smtp, cokolwiek innego. Tylko wtedy klasa MailSender nie może dziedziczyć po Mail - to by bez sensu było przecież. winksmiley.jpg


A czytałeś dołączony kod? Napisałem wyraźnie dziedziczenie ALBO dodatkowy obiekt.

Pozdrawiam smile.gif
Crozin
Czytałem, to albo też - tyle że z dziedziczeniem to zły pomysł - z dodatkowym obiektem jak najbardziej - dlatego się "czepiam". winksmiley.jpg
phpion
Cytat(LBO @ 20.04.2009, 09:16:06 ) *
A czytałeś dołączony kod? Napisałem wyraźnie dziedziczenie ALBO dodatkowy obiekt.

Dziedziczenie? Nie bardziej polimorfizm?

smile.gif
LBO
Cytat(Crozin @ 20.04.2009, 09:24:50 ) *
Czytałem, to albo też - tyle że z dziedziczeniem to zły pomysł - z dodatkowym obiektem jak najbardziej - dlatego się "czepiam". winksmiley.jpg


a Czemu zły? Ile razy Ci się zdarza zmieniać silnik wysyłający maile?
Fakt, wydzielenie obiektu wysyłającego jest elastyczne, ale wcale nie znaczy, że potrzebne. Czasami to zwykłe komplikowanie kodu.

  1. <?php
  2. abstract class Mail
  3. {
  4.    // settery i gettery
  5.  
  6.    abstract public function send();
  7. }
  8.  
  9. class BasicMail extends Mail
  10. {
  11.    public function send()
  12.    {
  13.        // tutaj używasz mail()
  14.    }
  15. }
  16.  
  17. class SmtpMail extends Mail
  18. {
  19.    // konstruktor z danymi konfiguracyjnymi do serwera
  20.  
  21.    public function send()
  22.    {
  23.        // a tutaj składasz nagłówki i odpowiedź dla serwera SMTP
  24.    }
  25. }
  26. ?>


I też bangla.

edit:

mały błędzik był smile.gif
mike
Cytat(LBO @ 20.04.2009, 09:35:43 ) *
a Czemu zły? Ile razy Ci się zdarza zmieniać silnik wysyłający maile?
Fakt, wydzielenie obiektu wysyłającego jest elastyczne, ale wcale nie znaczy, że potrzebne. Czasami to zwykłe komplikowanie kodu.
Bardzo często w środowisku deweloperskim masz inny mechanizm do wysyłki maili.
Że już nie wspomnę o testowaniu aplikacji. Podczas nich często zdarza się zmieniać silnik wysyłający maile.
PawelC
Cytat(Crozin)
Rada: jak najszybciej porzuć polskie nazewnictwo w kodzie

A to dlaczego?

No więc tak tutaj jest część kodu odpowiedzialna za dodanie adresata/adresu:
  1. <?php
  2. public function addAddressee($mail, $name){
  3.        //mail to adres, name to ładna nazwa trafiająca do nagłówka
  4.        $this->addressee[$mail] = $name;
  5.    }
  6. ?>

I jak zrobić to żeby, wczytać wszystkie maile i wysłać do każdego? Bo wczoraj napisałem kod który wczytuje, ale wysyłał tylko do jednej osoby, i kod wyglądał tak:
  1. <?php
  2.         class mail
  3.         {
  4.             public $nadawca;
  5.             public $odbiorca;
  6.             public $temat;
  7.             public $tresc;
  8.            
  9.            
  10.                     function __construct($nadawca)
  11.                     {
  12.                         $this -> nadawca = $nadawca;
  13.                         $this -> odbiorca = array();
  14.                     }
  15.                    
  16.                    
  17.                     public function ustawTemat($temat)
  18.                     {
  19.                         $this-> temat = $temat;
  20.                     }
  21.                    
  22.                    
  23.                     public function ustawTresc($tresc)
  24.                     {
  25.                         $this -> tresc= $tresc;
  26.                     }
  27.                    
  28.                    
  29.                     public function dodajOdbiorce()
  30.                        {
  31.                    
  32.                            $email=file('emaile.txt');
  33.                            foreach($email as $odbiorca)
  34.                            {
  35.                              array_push($this->odbiorca,$odbiorca);
  36.                              return $odbiorca;
  37.                             }
  38.                        }
  39.                    
  40.                    
  41.                     public function wyslijMaila()
  42.                     {
  43.                        
  44.                         foreach($this->odbiorca as $dokogo)
  45.                         {
  46.                         mail($dokogo,$this -> temat,$this->tresc,'From:'. $this->nadawca);
  47.                         }
  48.                     }
  49.         }
  50.        
  51. $mail=new mail('nadawca@wp.pl');
  52. $mail->dodajOdbiorce();
  53. $mail->ustawTemat('Temat testowy');
  54. $mail->ustawTresc('przykladowa tresc');
  55. $mail->wyslijMaila();
  56. ?>

Domyślam się, że gdzieś popełniłem pewnie parę błędów.
Crozin
Cytat
A to dlaczego?
1) Estetyka. Języki prog. same w sobie stosują ang. nazewnictwo (function, class, new, this, switch itp.) a mieszanie dwóch języków wygląda paskudnie:
Kod
private function mojaFunkcja(Iterator $parametr)

2) Kod pisany po polsku zrozumiały jest dla może kilkuset tysięcy osób - Polacy mający jakieś pojęcie o prog. Kod pisany po angielsku jest dostępny dla iluś tam milionów
3) Wszystkie dokumentacje etc. pisane są pierwotnie po angielsku.


Funkcja mail() może przyjąć jako pierwszy argument całą listę adresów mailowych na które ma wysłać maila - zobacz w manualu.
PrinceOfPersia
  1. <?php
  2. $mail=new mail('adres@wp.pl');
  3. $mail->ustawNadawce('ktos@adres.pl');
  4. $mail->ustawTemat('Temat testowy');
  5. $mail->ustawTresc('przykladowa tresc');
  6. $mail->wyslijMaila();
  7. ?>


a może lepiej nieco to uprościć, po co się męczyć i za każdym razem pisać $mail->ustawCośtam?

$mail=new mail('nadawca@wp.pl', 'biuro@cos.pl', 'Temat testowy', 'przykladowa tresc');
$mail->wyslijMaila();

tak łatwiej, lepiej i bardziej "obiektowo". W końcu do tego służą konstruktory. A jak będziesz miał kilku odbiorców to możesz przecież ich podać też w konstruktorze jako tablicę:
$odbiorcy = array('prezydent@polska.gov', 'premier@sejm.pl', 'ciocia_jadzia@gmail.com');
$mail=new mail('nadawca@wp.pl', $odbiorcy, 'Temat testowy', 'przykladowa tresc');
$mail->wyslijMaila();
a w funkcji wyslijMaila sprawdzasz czy $odbiorca jest tablica is_array($this->odbiorca) , i jak tak to przelatujesz foreach, a jak nie to wysyłaś tylko do jednego odbiorcy. Proste i elastyczne. Po wywaleniu funkcji dostępowych twoja klasa wydaje się dużo mniejsza i bardziej przejrzysta. A jeżeli jednak nie odpowiada Ci podawanie danych w konstruktorze (bo na przykład masz zamiar modyfikować twojego maila zanim go wyślesz) to poczytaj o metodach magicznych __set i __get
http://www.php.rk.edu.pl/w/p/metody-magiczne/

  1. <?php
  2. public $temat;
  3.  
  4.  ...
  5.  
  6.  public function ustawTemat($temat)
  7.  {
  8.      $this-> temat = $temat;
  9.  }
  10. ?>


No ale albo robisz zmienną $temat (i inne) publiczne, albo robisz prywatne i dopiero wtedy potrzebujesz metod dostępowych typu ustawTemat. Przecież jak masz public to możesz się normalnie, bez żadnych funkcji odwoływać do tych zmiennych poprzez $mail->temat = "dzieńdobry ciociu" w dowolnym miejscu kodu, o ile stworzyłeś wcześniej ten obiekt. Z tym, że takie "upublicznianie danych" nie jest wcale zalecane w programowaniu obiektowym i dlatego w trosce o prywatność obiektów robi się zmienne prywatne (private zamiast public przed nazwą ) conajwyżej udostępniając publiczną "metodę dostępową". Co najwyżej, bo czasami jest to zbyteczne. Na przykład jeśli treść danego maila się nie będzie zmieniała, tylko raz przypiszesz i już to równie dobrze można to umieścić w konstruktorze i już nie męczyć się i obiektu smile.gif

Cytat
Proszę o opinie, w szczególności czy mój tok rozumowania odnośnie tworzenia klas i używania w nich konstruktora jest dobry. Wiem że dla Was, napisanie takiej klasy to pikuś, ale dopiero raczkuje w OOP i chciałbym poznać waszą opinię.

Hmm... ja bym powiedział, że za dużo się napatrzyłeś w czyjś kod i przykłady, a brakuje Ci teoretycznego zrozumienia smile.gif wiesz "jak", ale nie wiesz "po co" smile.gif
LBO
Cytat(mike @ 20.04.2009, 09:43:38 ) *
Bardzo często w środowisku deweloperskim masz inny mechanizm do wysyłki maili.
Że już nie wspomnę o testowaniu aplikacji. Podczas nich często zdarza się zmieniać silnik wysyłający maile.

Hej mike, piszesz o mockowaniu obiektów? To rozumiem i się zgadzam.
Bardziej mi chodziło o podmianę sendera w czasie działania skryptu, bo przy takim bzdeciku nie widzę za bardzo innego zastosowania.
A tak nadal podtrzymuje moje dalsze słowa (których już nie skomentowałeś ;P)

Cytat
Fakt, wydzielenie obiektu wysyłającego jest elastyczne, ale wcale nie znaczy, że potrzebne. Czasami to zwykłe komplikowanie kodu.
dr_bonzo
Ja lubie zaczynac pisanie klas od drugiej strony, czyli od jej uzywania, potrzebujesz wyslac mailing do 1000 userow, kazdy dostanie ten sam email.
  1. <?php
  2. $emailSender=  new EmailSender($serverSMTP, 'user', 'haslo');
  3. $email = new Email( $title, $subject );
  4. foreach ( $users as $user )
  5. {
  6.    $emailSender->send( $email, $user->email );
  7. }
  8. ?>


a teraz stworz klasy ktore to wykonaja.

Dzieki temu stworzysz cos czego potrzebujesz, i cos co robi to czego pragniesz.
Nie bedziesz dopisywal 100tek metod ktorych nigdy nie uzyjesz (no chyba ze piszesz uniwersalna biblioteke - ale, tu masz uniwersalne potrzeby).

Potem okaze sie ze potrzebujesz czegos jezszce - poprawiasz, itd.
PawelC
Cytat(PrinceOfPersia)
Hmm... ja bym powiedział, że za dużo się napatrzyłeś w czyjś kod i przykłady, a brakuje Ci teoretycznego zrozumienia smile.gif wiesz "jak", ale nie wiesz "po co" smile.gif

No właśnie, bo w książce mało co jest napisane o przykładach.


dr_bonzo dzięki, może uda mi się coś wykombinować, z tego co widzę to będę musiał napisać dwie klasy:
EmailSender
Email
I napewno będę musiał zastosować dziedziczenie biggrin.gif

PrinceOfPersia z OOP mam jak narazie małe doświadczenie, a więc komplikuje sobie wszystko jak mogę biggrin.gif ponieważ nie jestem w tym płynny, ale się staram.

Crozin masz rację z tym nazewnictwem, mam znajomego programistę i to samo mówił o nazewnictwie co Ty
Crozin
Cytat
I napewno będę musiał zastosować dziedziczenie
Tylko nie zrób telefonistki dziedziczącej po telefonie
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.