Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: OOP i problem z __construct
Forum PHP.pl > Forum > PHP
spokoloko123
Jako, że jestem nowy w OOP to za bardzo nie wiem dlaczego w tym kodzie (z książki) jest błąd. Wg. autora powinno być dobrze ale nie jest. Problem rozwiązują szybkie zmiany w kodzie ale nie o to mi chodzi. Raczej szukał bym jakiejś literówki ewentualnie wytłumaczenia dlaczego nie działa wink.gif

  1. <?php
  2. // class.emailer.php
  3. class Emailer
  4. {
  5. protected $sender;
  6. private $recipients;
  7. private $subject;
  8. private $body;
  9.  
  10. function __construct($sender)
  11. {
  12. $this->sender = $sender;
  13. $this->recipients = array();
  14. }
  15.  
  16. public function addRecipients($recipient)
  17. {
  18. array_push($this->recipients, $recipient);
  19. }
  20. public function setSubject($subject)
  21. {
  22. $this->subject = $subject;
  23. }
  24. public function setBody($body)
  25. {
  26. $this->body = $body;
  27. }
  28. public function sendEmail()
  29. {
  30. foreach ($this->recipients as $recipient)
  31. {
  32. $result = mail($recipient, $this->subject, $this->body,
  33. "From: {$this->sender}\r\n");
  34. if ($result) echo "Wiadomość została wysła do
  35. {$recipient}<br/>";
  36. }
  37. }
  38. }
  39.  
  40. class ExtendedEmailer extends Emailer
  41. {
  42.  
  43.  
  44. function __construct(){}
  45.  
  46. public function setSender($sender)
  47. {
  48. $this->sender = $sender;
  49. }
  50. }
  51.  
  52. $xemailer = new ExtendedEmailer();
  53. $xemailer->setSender("JA");
  54. $xemailer->addRecipients("user1@localhost");
  55. $xemailer->addRecipients("user2@localhost");
  56. $xemailer->setSubject("extended email");
  57. $xemailer->setBody("<h1>Extended</h1>");
  58. $xemailer->sendEmail();
  59.  
  60. ?>


Wynik skryptu wygląda tak:
  1. Warning: array_push() expects parameter 1 to be array, null given in C:\xampp\htdocs\OOP\ex2.1.php on line 18
  2.  
  3. Warning: array_push() expects parameter 1 to be array, null given in C:\xampp\htdocs\OOP\ex2.1.php on line 18
  4.  
  5. Warning: Invalid argument supplied for foreach() in C:\xampp\htdocs\OOP\ex2.1.php on line 30
Psajkus
nadpisujesz konstruktor w klasie ExtendedEmailer.
redeemer
Nie wywołujesz konstruktora klasy po której dziedziczysz.
mortus
Cytat(redeemer @ 8.05.2012, 15:53:25 ) *
Nie wywołujesz konstruktora klasy po której dziedziczysz.

Raczej jest tak, jak napisał Psajkus. spokoloko123 przeciąża konstruktor klasy, po której dziedziczy, wobec czego kod tego konstruktora nie jest wykonywany. Przeciążenia takiego powinniśmy dokonać wtedy, gdy klasa ExtendedEmailer będzie np. ustawiać dodatkowe właściwości/pola istotne dla tej właśnie klasy. Jeśli nie ma takiej potrzeby, to nie musimy przeciążać konstruktora i deklaracje funkcji __construct() w klasie dziedziczącej powinniśmy pominąć.

Edycja:
Wobec powyższego klasa ExtendedMailer mogłaby wyglądać po prostu tak:
  1. class ExtendedMailer extends Mailer {
  2. public function setSender($sender) {
  3. $this->sender = $sender;
  4. }
  5. }
  6. // a jej wywołanie
  7. $xmailer = new ExtendedMailer('sender');
  8. // mogłaby wyglądać również tak
  9. class ExtendedMailer extends Mailer {
  10. public function __construct($sender = null) {
  11. parent::construct($sender);
  12. }
  13. public function setSender($sender) {
  14. $this->sender = $sender;
  15. }
  16. }
  17. // a jej wywołanie
  18. $xmailer = new ExtendedMailer();
  19. $xmailer->setSender('sender');

Przy czym drugi sposób nie jest do końca prawidłowy, bo umożliwia utworzenie obiektu Mailera, który nie posiada "właściciela" (czyli osoby, która może z tego mailera korzystać (identyfikowanej po adresie e-mail)).
spokoloko123
Okazało się to erratą w książce. Dla przyszłych pokoleń:
  1. <?php
  2. // class.emailer.php
  3. class Emailer
  4. {
  5. protected $sender;
  6. protected $recipients;
  7. private $subject;
  8. private $body;
  9.  
  10. public function addRecipients($recipient)
  11. {
  12. array_push($this->recipients, $recipient);
  13. }
  14. public function setSubject($subject)
  15. {
  16. $this->subject = $subject;
  17. }
  18. public function setBody($body)
  19. {
  20. $this->body = $body;
  21. }
  22. public function sendEmail()
  23. {
  24. foreach ($this->recipients as $recipient)
  25. {
  26. $result = mail($recipient, $this->subject, $this->body,
  27. "From: {$this->sender}\r\n");
  28. if ($result) echo "Wiadomość została wysła do
  29. {$recipient}<br/>";
  30. }
  31. }
  32. }
  33.  
  34. class ExtendedEmailer extends Emailer
  35. {
  36.  
  37. function __construct()
  38. {
  39. $this->recipients = array();
  40. }
  41. public function setSender($sender)
  42. {
  43. $this->sender = $sender;
  44. }
  45. }
  46.  
  47. $xemailer = new ExtendedEmailer();
  48. $xemailer->setSender("JA");
  49. $xemailer->addRecipients("user1@localhost");
  50. $xemailer->addRecipients("user2@localhost");
  51. $xemailer->setSubject("extended email");
  52. $xemailer->setBody("<h1>Extended</h1>");
  53. $xemailer->sendEmail();
  54.  
  55. ?>
Crozin
Nadal nie jest to coś co można by nazwać poprawnym kodem. Klasa Emailer w metodzie addRecipients() zakłada, że właściwość recipients jest tablicą w momencie gdy tak na prawdę nie jest. Poniższy kod wywali błąd:
  1. $emailer = new Emailer(); // Klasa ta nie jest abstrakcyjna, więc nic nie stoi na przeszkodzie by utworzyć jej istancję
  2. $emailer->addRecipients("user1@localhost");
Tak więc jak już to:
  1. class Emailer {
  2. ...
  3.  
  4. public function __construct() {
  5. $this->recipients = array();
  6. }
  7. }
  8.  
  9. class ExtendedEmailer {
  10. public function __construct() {
  11. parent::__construct();
  12.  
  13. // Kod konstruktora specyficzny dla tej klasy
  14. }
  15. }


PS. Skoro metoda addRecipients() dodaje tylko jednego odbiorcę, to czy nie powinna nazywać się addRecipient()?
spokoloko123
1. Dodaje paru (gdy dziedziczona)
2. Kod z przykładu w książce, nie mój
3. Tak, wywali ale nie jest to problem, bo jest używana tylko jako dziedziczenie (wiem głupie, patrz punkt 2) oneeyedsmiley02.png .
4. Dlaczego są te nawiasy klamrowe? np:
  1. echo "Wiadomość została wysła do
  2. {$recipient}<br/>";


Dzięki za zainteresowanie.
bastard13
Abstrahując od Twojego problemu, który już został rozwiązany, to wydaje mi się, że hierarchia, którą tutaj przedstawiłeś jest totalnie bez sensu i nazywanie tego OOP jest 'lekkim' przekłamaniem. Jeżeli taki przykład jest w książce, to wrzuć tytuł, aby przyszłe pokolenia programistów po coś takiego nie sięgały:)

Dlaczego przykład jest zły?
Klasa ExtendedEmailer jest całkowicie nie potrzebna i tworzona chyba tylko po to, aby zrobić dziedziczenie. Wszystko co się w niej dzieje, to nadpisanie konstruktora i utworzenie metody setSender(), która poprzez swoją logikę wymusza zmianę widoczności atrybutu sender w klasie nadrzędnej na protected (czego również warto unikaćsmile.gif.
Jeżeli istnieje sytuacja, że klasę tworzysz bez sendera i dodajesz go później (setSender()), to na co Ci nowa klasa? Wystarczy zmienić konstruktor w klasie Emailer tak, żeby parametr był opcjonalny i do tej klasy dodać metodę setSender(). I po sprawie.

Nadmierne dziedziczenie stwarza wiele problemów (pewnie nawet jest to jakiś antywzorzec:P).

Dodatkowa rada, to nie zmieniaj deklaracji metody jeżeli rozszerzasz klasę tzn. jeżeli deklaracja klonstruktora w klasie rodzica jest: __construct($sender), to w klasach podrzędnych również taka powinna być.
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.