Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Wyjątek zamiast Notice
Forum PHP.pl > Forum > PHP > Object-oriented programming
solr
Mam dwie klasy:

  1. class Test {
  2. public $name;
  3. }
  4.  
  5. /*******/
  6.  
  7. class MyClass {
  8. private $_test = NULL;
  9.  
  10. __get($name)
  11. {
  12. return $this->$name;
  13. }
  14.  
  15. __set($name,$value)
  16. {
  17. $this->$name = $value;
  18. }
  19. }


Prawidłowe użycie tego to np. :

  1. $obj1 = new MyClass();
  2. $obj1->_test = new Test();
  3. $obj1->_test->name = 'Test!';


Wtedy wszystko działa jak chcę. Ale jest też możliwość, że ktoś użyje tego tak:

  1. $obj1 = new MyClass();
  2. $obj1->_test->name = 'Test!';


W wyniku czego dostaje notice: "Notice: Indirect modification of overloaded property MyClass::$_test has no effect in /not_important_path_here". Chciałbym nie dopuścić do takiej sytuacji. Zamiast notice chciałbym wyrzucić wyjątek. Jak to zrobić?
wookieb
Jedna z metod to będzie stworzenie errorHandlera który będzie wyrzucał wyjątek
set_error_handler
solr
To jest dobra odpowiedź, znam i używam tej funkcji, ale nie o to mi chodziło. Niedokładnie sformułowałem pytanie. Podana przez Ciebie funkcja jest wywoływana w momencie, gdy wystąpi np. notice. Z różnych powodów nie chcę tego zrobić w ten sposób. Chciałbym w ogóle nie dopuścić do wywołania notice, poprzez jakąś instrukcję warunkową najlepiej. Prawdopodobnie nie ma takiej możliwości, ale nie jestem pewny, więc pytam.
Crozin
Zacznijmy od tego, że za takie coś jak w klasie MyClass powinno się dostać dwa razy po mordzie - najlepiej od Pudziana. winksmiley.jpg

1. Staraj się unikać wszelakiej magii w swoim kodzie - ona zawsze tylko niepotrzebnie komplikuje sprawę. Nie wiem po co to w ogóle wprowadzano do PHP (chociaż czasami jest to przydatne gdy musimy zmienić interfejs obiektu).
2. Co to za problem dodać w metodzie get/set warunek sprawdzający istnienie danego elementu i rzucający wyjątek w przypadku gdy takowy nie istnieje?
wookieb
A chyba, że tak
Problem jest następujący:
Jeżeli nie ma takiej wartości w obiekcie powinno zwracać się null. W twoim wypadku powinien to być obiekt, który wyrzuca dodatkowe wyjątki.
Przykład
  1. class InvalidPropertyName
  2. {
  3.  
  4. public function __get($name)
  5. {
  6. throw new InvalidArgumentException('Undefined value for property "'.$name.'"');
  7. }
  8.  
  9. public function __set($name, $value)
  10. {
  11. throw new InvalidArgumentException('Undefined value for property "'.$name.'"');
  12. }
  13. }
  14. class MyClass {
  15. private $_test = NULL;
  16.  
  17. public function __get($name)
  18. {
  19. if (isset($this->$name)) return $this->$name;
  20. return new InvalidPropertyName();
  21. }
  22.  
  23.  
  24. public function __set($name,$value)
  25. {
  26. $this->$name = $value;
  27. }
  28. }
  29.  
  30. $o = new MyClass;
  31. $o->test->hehe = 'cos';

Aczkolwiek jak pewnie się domyślasz rodzi to wiele problemów:
- przede wszystkim nigdy nie dostaniesz null-a z MyClass
- Nie zwracanie null jest bardzo kłopotliwe

Szczerze mówiąc odradzam takie rozwiązanie. Może opiszesz jaki masz problem, który spowodował używanie takiego kodu jaki masz, to razem znajdziemy jakis sposób.
solr
@Crozin
1) Dzięki za zwrócenie na to uwagi - zainteresuje się tematem głębiej w wolnej chwili. Btw. __construct() to też magiczna metoda, starasz się unikać? ;-)
2) Z powodów wyjaśnionych już przez wookieb.

@wookieb
Nie zwracanie Null to za wysoka cena. Generalnie nie ma problemu wielkiego z tym co chcę zrobić. Zauważyłem tylko, że istnieje możliwość popełnienia błędu w tym miejscu i chciałem tą możliwość usunąć. Natomiast co chciałem zrobić ogólnie to: stworzyć obiekt, który BĘDZIE MÓGŁ (ALE NIE MUSI) zawierać w sobie instancję innej klasy. W jaki sposób radzisz sobie z tym problemem bez wykorzystania NULL?
wookieb
Tworzę go jeżeli nie ma a dobrze by było gdyby jednak istniał. Jeżeli niekoniecznie musi istnieć to sprawdzam na tym etapie
  1. $k = new MyClass;
  2. $test = $k->_test;
  3. if ($test) {
  4. // jedziem dalej
  5. $test->name = 'cos';
  6. }
Crozin
Cytat
Btw. __construct() to też magiczna metoda, starasz się unikać? ;-)
Chodziło mi o prawdziwie magiczne potworki typu get/set/call, których zasada działania jest "magiczna". Działanie metod typu construct/destruct/toString jest "normalne".

Szczerze powiedziawszy to pogubiłem się w tym co próbujesz zrobić, dlatego ponowię prośbę wookieba: napisz jaki masz dokładnie problem, bo być może kombinujesz w złą stronę.
Pilsener
Przecież właśnie dlatego dostęp do innej klasy odbywa się przez jej interfejs a nie bezpośrednio, co gwarantuje, że każda klasa jest spójna, logiczna i przemyślana, co to za klasa, która służy jako "worek na publiczne zmienne"? W dodatku nie ma żadnego sposobu na sprawdzenie, czy ta zmienna ma tam być, czy ma poprawny typ czy przedział wartości... okropieństwo.
wookieb
Cytat(Pilsener @ 23.09.2010, 21:19:18 ) *
co to za klasa, która służy jako "worek na publiczne zmienne"?

Np kontener danych dla szablonów?

dariuszp
Nie tylko. Widziałem również obiekty danych skonstruowane z "magią". Wewnątrz klasy mamy prywatny atrybut zawierający tablicę. Tablica odpowiada bazie danych. Taki obiekt danych to reprezentacja jednego wiersza w bazie danych.
Wykonując operacje w stylu $obj->var = 'test'; $obj->save($mapper); $obj->delete($mapper); itp modyfikujemy wybrane rekordy w bazie danych.

No i dzięki magicznym metodą takie obiekty danych mogą być tworzone dla dowolnej tabeli w bazie danych. Nie trzeba deklarować szeregu akcesorów dla każdego obiektu (pomijam fakt że w czasie jednego wywołania metody magicznej możemy wywołać kilka zwykłych metod). Nie mniej jednak niektórzy wychodzą z założenia że czas procesora jest mniej wart jak czas programisty. Osobiście uważam że to prawda ale nie należy popadać w skrajność.

Inne zastosowania ?
= kontener danych dla szablonów
= zbiornik danych (widziałem system modułowy którego moduły zrzucały dane do obiektu zewnętrznego z którego inne moduły mogły sobie te dane pobrać - nie w PHP akurat)
= rejestr (czegokolwiek, zdarzeń, błędów, zapytań, danych, co sobie wymarzycie)
= śmietnik (jak głupio by to brzmiało, bywa że usuwamy coś z systemu czego nie można objąć transakcją i na wszelki wypadek coś innego może to przywrócić lub wykorzystać)
cokolwiek...

Pomysłów jest tyle ile widziałem projektów. Programiści mają nieraz genialne a nieraz chore pomysły. A z takimi narzędziami jak z prezerwatywą. Lepiej mieć i nie potrzebować jak potrzebować i nie mieć.

To co robi autor jest błędne. Możecie napisać własny mechanizm obsługi błędów ale te i tak pozostaną. Jeżeli chcesz mieć pewność że $_test zawsze będzie miało obiekt to stwórz ten obiekt w konstruktorze. Osobiście po prostu radzę napisać mechanizm który będzie Ci logował gdzieś takie błędy (do pliku najlepiej) a Ty powoli zmieniaj przyzwyczajenia programistyczne.

Jeżeli potrzebujesz tam obiekt to wcześniej po prostu UPEWNIJ się że tam będzie zamiast szukać niepotrzebnie drogi na około.
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.