Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][OOP] Metoda __set nie działa?
Forum PHP.pl > Forum > Przedszkole
djgarsi
Witam serdecznie.
Rozpocząłem naukę PHP OOP i jak to zwykle bywa, napotkałem problem i nie wiem o co chodzi.
Otóż mam klasą:
  1. <?php
  2.  
  3. class Samochod {
  4. public $predkosc_maksymalna;
  5.  
  6. function __set($nazwa, $wartosc) {
  7. if (($nazwa == "predkosc_maksymalna") && ($wartosc > 0) && ($wartosc < 350)) {
  8. $this->predkosc_maksymalna = $wartosc;
  9. }
  10. else {
  11. echo "Za szybko, zwolnij!";
  12. }
  13. }
  14. }
  15.  
  16. $pojazd = new Samochod;
  17. $pojazd->$predkosc_maksymalna = 200;
  18.  
  19. echo $pojazd->predkosc_maksymalna;
  20. ?>


Przy każdej wartości (np. 200) wyrzuca, że "za szybko" a jak wiadomo przy 200 powinno działać normalnie.
Proszę o pomoc.
viking
  1. $pojazd->predkosc_maksymalna = 200; //bez $


Poza tym dodaj tam sobie w ifie echo 'wykonałem';, poczytaj dokumentację http://www.php.net/manual/en/language.oop5....php#object.set zwłaszcza
Cytat
/** Overloading not used on declared properties. */
public $declared = 1;
i zastanów się dlaczego to jest źle.
djgarsi
Cytat(viking @ 30.04.2013, 18:52:01 ) *
  1. $pojazd->predkosc_maksymalna = 200; //bez $


Poza tym dodaj tam sobie w ifie echo 'wykonałem';, poczytaj dokumentację http://www.php.net/manual/en/language.oop5....php#object.set zwłaszcza
i zastanów się dlaczego to jest źle.



No dobra, usunąłem $, dodałem echo w if'ie i ustawiłem public $predkosc_maksymalna=0;.
Sytuacja wygląda teraz tak, że wyświetla po prostu wartość prędkości, tak jakby pomijało całkiem if'a.
mortus
Przeciążone metody magiczne nie operują na właściwościach publicznych, bo te z założenia są dostępne za pomocą operatora wyłuskania ->. Dlatego metoda __set() nie jest w ogóle u Ciebie uruchamiana.

Pisałem już o tym szerzej na tym forum.

No i oczywiście największy sens ma przechowywanie danych, do których chcemy mieć dostęp za pomocą operatora wyłuskania (i przeciążonych metod __set() i __get()) w prywatnej tablicy.
djgarsi
Kurcze, takie niuanse podczas nauki OOP.

@mortus: mógłbyś bardziej łopatologicznie napisać o co chodzi z tymi metodami __set i __get?
CuteOne
  1. class Registry {
  2.  
  3. private $_data = array();
  4.  
  5. public function __set($key, $value) {
  6.  
  7. $this->_set($key, $value);
  8. return $this;
  9. }
  10.  
  11. private function _set($key, $value) {
  12.  
  13. $this->_data[$key] = $value;
  14. }
  15.  
  16. public function __get($key) {
  17. if(isset($this->_data[$key]) {
  18. return $this->_data[$key]; //lub $this->_get($key);
  19. }
  20. }
  21. ....


Metody _set i _get mogą być publiczne,chronione lub jak w powyższym przykładzie prywatne. Cały trick polega na tym, że dane przechowujesz w tablicy (możesz np. zabezpieczyć je przed nadpisaniem)
mortus
@CuteOne: Metody magiczne powinny być publiczne, bo oczekujemy publicznego/globalnego dostępu do nich. Niemniej metody zadeklarowane jako prywatne również działają, co jest karygodnym błędem twórców PHP (zdaje się że w wersji 5.3 PHP pojawiał się w tej sytuacji WARNING).

Jednak nie o to mi chodziło we wcześniejszej odpowiedzi. Łopatologicznie:
przykład, w którym nie korzystamy z metod __set() i __get()
  1. class A {
  2. public $a;
  3. public function __set($key, $value) {
  4. $this->$key = $value;
  5. }
  6. public function __get($key) {
  7. return $this->$key;
  8. }
  9. }
  10. $o = new A;
  11. $o->a = 10;
  12. echo $o->a;

Ponieważ właściwość $a klasy A jest właściwością publiczną, mamy do niej bezpośredni dostęp za pomocą operatora wyłuskania -> i magiczne metody __set() i __get() nie będą w tej sytuacji wywoływane.

przykład, w którym korzystamy z metod __set() i __get()
  1. class A {
  2. private $a;
  3. public function __set($key, $value) {
  4. $this->$key = $value;
  5. }
  6. public function __get($key) {
  7. return $this->$key;
  8. }
  9. }
  10. $o = new A;
  11. $o->a = 10;
  12. echo $o->a;

Ponieważ właściwość $a klasy A jest właściwością prywatną, nie mamy do niej bezpośredniego dostępu za pomocą operatora wyłuskania -> i tutaj potrzebujemy magicznych metod __set() i __get() - tutaj będą one wywoływane.

Niemniej wykorzystanie tych metod magiczny w ten sposób jest bez sensu, bo musielibyśmy dokładnie kontrolować wszystkie właściwości klasy. Rozwiązanie, które podał CuteOne ma zdecydowanie większy sens.
djgarsi
Super. Chyba rozumiem. Mój kod będzie teraz poprawny?
  1. class Samochod {
  2. private $predkosc_maksymalna;
  3.  
  4. function __set($nazwa, $wartosc) {
  5. if (($nazwa == "predkosc_maksymalna") && ($wartosc > 0) && ($wartosc < 350)) {
  6. $this->predkosc_maksymalna = $wartosc;
  7. echo "Predkosc ok.";
  8. }
  9. else {
  10. echo "Za szybko, zwolnij!";
  11. }
  12. }
  13. public function __get($wartosc) {
  14. return $this->predkosc_maksymalna;
  15. }
  16. }
  17.  
  18. $pojazd = new Samochod;
  19. $pojazd->predkosc_maksymalna = 200;
  20.  
  21. echo $pojazd->predkosc_maksymalna;
mortus
Przede wszystkim takie użycie metod __set() i __get() nie ma praktycznego zastosowania, bo zmusza programistę do kontrolowania wszystkich właściwości klasy (trzeba znać dokładnie nazwy tych właściwości). Lepiej użyć, jak już zwracaliśmy uwagę, tablicy:
  1. class Car {
  2. private $features = array();
  3. public function __set($key, $value) {
  4. $this->features[$key] = $value;
  5. }
  6. public function __get($key) {
  7. return $this->features[$key];
  8. }
  9. }
  10. $car = new Car;
  11. $car->max_speed = 200;
  12. var_dump($car);

Poza tym źle napisałeś metodę __get(), gdybyś miał np. pole prywatne kolor i próbował pobrać wartość tego pola za pomocą $pojazd->kolor, to nadal otrzymasz wartość prędkości maksymalnej.

No i w końcu to co stricte dotyczy OOP, settery i gettery (również te magiczne) nie są dobrym miejscem do kontrolowania wartości zmiennych. Powinna do tego raczej służyć osobna metoda np. sprawdzPredkosc().

I jeszcze jedno... takie przeciążone metody __set() i __get() raczej nie nadają się do powszechnego użytku (w ogóle nie pasują do klasy Samochod). Zdecydowanie lepszy przykład podał CuteOne - klasa Rejestr, która ma za zadanie przechowywać dowolne lecz istotne dane dla naszej aplikacji. W klasie Samochod lepiej będzie wykorzystać po prostu setPredkoscMaksymalna() i getPredkoscMaksymalna().
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.