Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Prośba o sprawdzenie klasy
Jarod
post
Post #1





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


W książce natrafiłem na przykład, który wydaje mi się błędny. Wiem, że książki helionu mają literówki i różnego rodzaju błędy (na stronie helionu w erracie nie ma poprawki do tego), dlatego proszę o sprawdzenie poniższego kodu.


  1. <?php
  2. interface Validator{
  3. abstract function validate();
  4. }
  5. ?>


  1. <?php
  2. require_once('interface.Validator.php');
  3.  
  4. abstract class PropertyObject implements Validator {
  5.  
  6. protected $propertyTable = array();  //Przechowuje pary nazwa-wartość przypisujące
  7. //własności do pól bazy danych
  8. protected $changedProperties = array(); //Lista własności które zostały zmodyfikowane
  9. protected $data; //Dane z bazy
  10. protected $errors = array();
  11.  
  12. public function __construct($arData) {
  13. $this->data = $arData;
  14. }
  15.  
  16. function __get($propertyName) {
  17. if (!array_key_exists($propertyName, $this->propertyTable))
  18. throw new Exception('Błędna własność '.$propertyName.'!');
  19.  
  20. if (method_exists($this, 'get' , $propertyName)) {
  21. return call_user_func(array($this, 'get' , $propertyName));
  22. }
  23. else { 
  24. return $this->data[$this->propertyTable[$propertyName]];
  25. }
  26. }
  27.  
  28.  
  29. function __set($propertyName, $value) {
  30. if (!array_key_exists($propertyName, $this->propertyTable))
  31. throw new Exception('Błędna własność '. $propertyName.' !');
  32.  
  33. if (method_exists($this, 'set' , $propertyName)) {
  34. return call_user_func(array($this, 'set' , $propertyName), $value);
  35. }
  36. else { 
  37. if ($this->propertyTable[$propertyName] != $value &&
  38.  !in_array($propertyName, $this->changedProperties)) {
  39.  $this->changedProperties[] = $propertyName;
  40. }
  41.  
  42. $this_>data[$this->propertyTable[$propertyName]] = $value;
  43. }
  44. }
  45.  
  46. function validate() {
  47.  
  48. }
  49. }
  50. ?>


I teraz ten kod gdzie podejrzewam, że jest błąd..

  1. <?php
  2. reguire_once ('class.PropertyObject.php');
  3.  
  4. class Address extends PropertyObject {
  5.  
  6. function __construct($addressid) {
  7. $arData = DataManager::getAddressData($addressid);
  8.  
  9. parent::__construct($arData);
  10.  
  11. $this->propertyTable['addressid'] = 'adres_id';
  12. $this->propertyTable['id'] = 'adres_id';
  13. $this->propertyTable['entityid'] = 'jednostka_id';
  14. $this->propertyTable['address1'] = 'sadres1';
  15. $this->propertyTable['address2'] = 'sadres2';
  16. $this->propertyTable['city'] = 'smiasto';
  17. $this->propertyTable['zipcode'] = 'skod';
  18. $this->propertyTable['type'] = 'styp';
  19. }
  20.  
  21.  
  22.  function validate () {
  23.  
  24.  if (strlen($this->zipcode) != 6) {
  25.  $this->errors['zipcode'] = 'Należy podać poprawny kod pocztowy.';
  26.  } 
  27.  
  28.  if ($this->address1) {
  29.  $this->errors['address1'] = 'Adres to pole wymagane';
  30.  } 
  31.  
  32.  if ($this->city) {
  33.  $this->errors['city'] = 'Miasto to pole wymagane';
  34.  } 
  35.  
  36.  if (sizeof($this->errors)) {
  37.  return false;
  38.  } else {
  39.  return true;
  40.  }
  41.  
  42.  }
  43. }
  44. ?>


Wydaje mi się, że błąd jest w metodzie validate(). Autor odwołuje suię w ten sposób
  1. <?php
  2. if ($this->address1) {
  3.  $this->errors['address1'] = 'Adres to pole wymagane';
  4.  }
  5. ?>


a powinno być chyba
  1. <?php
  2. if ($this->propertyTable['address1']) {
  3.  $this->errors['address1'] = 'Adres to pole wymagane';
  4.  }
  5. ?>


jeśli nie to dlaczego właśnie tak?
Go to the top of the page
+Quote Post
envp
post
Post #2





Grupa: Zarejestrowani
Postów: 359
Pomógł: 1
Dołączył: 16.04.2006
Skąd: Łódź

Ostrzeżenie: (0%)
-----


Zauważ, że masz funkcje __get() oraz __set() - pierwsza wykorzystywana jest wtedy kiedy robisz

  1. <?php
  2. echo $obiekt->cos;
  3. ?>


druga kiedy:
  1. <?php
  2. $obiekt->cos = 'lalalal';
  3. ?>


Nawet, kiedy pole cos nie istnieje. Opisalem to tutaj:
envp's devblog
Go to the top of the page
+Quote Post
Ludvik
post
Post #3





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Nie podoba mi się ten kod. Po pierwsze właściwość nie jest walidatorem, co najwyżej może być walidowana (czyli raczej Validable). Poza tym nie rozumiem, po co deklarować metodę validate, w klasie PropertyObject... Jest to typowy przykład zastosowania metody abstrakcyjnej, a nie bezsensownego wklepywania pustej...

Tak poza tym, to dlaczego my mamy to sprawdzać? Więcej się nauczysz, jak sam będziesz chciał to sprawdzić... Odpal skrypt, zdebuguj go xdebugiem czy czymś innym...
Go to the top of the page
+Quote Post
Jarod
post
Post #4





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


Cytat(Ludvik @ 16.08.2006, 13:29 ) *
Nie podoba mi się ten kod. Po pierwsze właściwość nie jest walidatorem, co najwyżej może być walidowana (czyli raczej Validable). Poza tym nie rozumiem, po co deklarować metodę validate, w klasie PropertyObject... Jest to typowy przykład zastosowania metody abstrakcyjnej, a nie bezsensownego wklepywania pustej...


Coraz częściej dochodze do wniosku, że ta książka jest bardzo zamotana. Chyba tylko po to, żeby więcej stron było.

Cytat(envp @ 16.08.2006, 10:26 ) *
Zauważ, że masz funkcje __get() oraz __set() - pierwsza wykorzystywana jest wtedy kiedy robisz


Ok. Powoli łapie. Ale nie mogę zrozumieć tego kawałka kodu (z metody __get() ):
  1. <?php
  2. if (method_exists($this, 'get' , $propertyName)) {
  3. return call_user_func(array($this, 'get' , $propertyName));
  4. }
  5. else { 
  6. return $this->data[$this->propertyTable[$propertyName]];
  7. ?>


Po co sprawdza się czy metoda istnieje. Nie łapie też argumentów tej metody oraz call_user_func. Czytałem o tych funkjach ale nie mogę załapać. Możecie mi to wytłumaczyć?
Go to the top of the page
+Quote Post
Ludvik
post
Post #5





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Przepisałeś błędnie niektóre wywołania metod. Zamiast kropki (operator łączenia łańcuchów znakowych) wstawiłeś przecinek.
  1. <?php
  2. method_exists($this, 'get' . $propertyName)
  3. ?>

call_user_func" title="Zobacz w manualu php" target="_manual... Manual na pewno Ci wyjaśni znaczenie parametrów.
Całe to zamieszanie jest po to, aby korzystać z metod getNazwaWłaściwości zamiast bezpośredniego odwoływania się do tablicy z danymi. Jeżeli nie istnieje metoda pobierająca dane, wtedy zwracana jest wartość bezpośrednio z tablicy...
Go to the top of the page
+Quote Post
Jarod
post
Post #6





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


Cytat(Ludvik @ 17.08.2006, 08:58 ) *
Przepisałeś błędnie niektóre wywołania metod. Zamiast kropki (operator łączenia łańcuchów znakowych) wstawiłeś przecinek.
  1. <?php
  2. method_exists($this, 'get' . $propertyName)
  3. ?>

Tak mam w książce. Ale naet jak powinna być kropka to nie ma sensu zapis $this.get.propertyName.
Nie powinno być:
  1. <?php
  2. method_exists($this->'get'->$propertyName)
  3. ?>

?
Ogólnie w manulu piszą, że funkcja method_exists pobiera dwa parametry: instancje klasy, metode.

Nie łapie tego. Zresztą przecież jak mamy metode magiczną __get() to nie odwołujemy się do niej przez $this->cos tylko $this->cos();


Cytat(Ludvik @ 17.08.2006, 08:58 ) *
call_user_func" title="Zobacz w manualu php" target="_manual... Manual na pewno Ci wyjaśni znaczenie parametrów.

Sprawdzałem. Podobnie jak w z method_exists nie rozumiem po co w środek wstawiane jest to get i array..

Cytat(Ludvik @ 17.08.2006, 08:58 ) *
Całe to zamieszanie jest po to, aby korzystać z metod getNazwaWłaściwości zamiast bezpośredniego odwoływania się do tablicy z danymi. Jeżeli nie istnieje metoda pobierająca dane, wtedy zwracana jest wartość bezpośrednio z tablicy...

Jaki jest sens? Przecież pisząć aplikacje pisze metodę, która pobiera dane, bo wiem, że tego będę potrzebował. I nie ma sensu mówić, że nad proejktem może pracować wiele osób. Bo nawet w takim przypadku jeden programista pisze i kończy daną klase i powinien takie metody dostępowe utworzyć..
Go to the top of the page
+Quote Post
Ludvik
post
Post #7





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Powinno być
  1. <?php
  2. method_exists($this, 'get' . $propertyName)
  3. ?>

Pierwszy argument to instancja klasy. Drugi argument ('get' . $propertyName) to nazwa metody. Nie widzę nic dziwnego w tym wywołaniu...

Dalej...
  1. <?php
  2. call_user_func(array($this, 'get' . $propertyName));
  3. ?>

Tak samo... Pierwszy argument ma być typu callback. Jest to nazwa funkcji albo w przypadku wywoływania metod tablica. Pierwszy elementem tablicy jest referencja do obiektu (albo nazwa klasy, jeżeli wywołujemy statyczną metodę). Drugi element to nazwa metody.

Oni to zrobili po to, aby przeciążyć "magiczne" metody, ale nie tracić zachowania metod programisty getXXX... Jeżeli istnieje metoda getWlasciwosc, a ty poprosisz o dane tak:
  1. <?php
  2. echo $obj->wlasciwosc;
  3. ?>

To i tak efektem będzie wywołanie metody getWlasciwosc...
Go to the top of the page
+Quote Post
Jarod
post
Post #8





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


Cytat(Ludvik @ 17.08.2006, 09:27 ) *
Powinno być
  1. <?php
  2. method_exists($this, 'get' . $propertyName)
  3. ?>

Pierwszy argument to instancja klasy. Drugi argument ('get' . $propertyName) to nazwa metody. Nie widzę nic dziwnego w tym wywołaniu...

$this nie jest instancją klasy(?) getNazwaMetody samo w sobie nie jest dziwne. Dziwne jest to, że w przykładzie, który podałem na samym początku nie ma metody. Jest tylko magiczna (czyli jak dobrze przeczytałem wywoływana automatycznie gdy ktoś chce wywołać nieistniejącą metode), nie ma żadnej innej metody.


Cytat(Ludvik @ 17.08.2006, 09:27 ) *
Dalej...
  1. <?php
  2. call_user_func(array($this, 'get' . $propertyName));
  3. ?>

Tak samo... Pierwszy argument ma być typu callback. Jest to nazwa funkcji albo w przypadku wywoływania metod tablica. Pierwszy elementem tablicy jest referencja do obiektu (albo nazwa klasy, jeżeli wywołujemy statyczną metodę). Drugi element to nazwa metody.

Oni to zrobili po to, aby przeciążyć "magiczne" metody, ale nie tracić zachowania metod programisty getXXX... Jeżeli istnieje metoda getWlasciwosc, a ty poprosisz o dane tak:
  1. <?php
  2. echo $obj->wlasciwosc;
  3. ?>

To i tak efektem będzie wywołanie metody getWlasciwosc...


Thx.
Go to the top of the page
+Quote Post
Ludvik
post
Post #9





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


$this jest referencją do obiektu, którego metoda jest wywoływana, czyli po ludzku - do samego siebie. Przy odczycie/przekazywaniu nie różni się niczym od innych referencji.
Go to the top of the page
+Quote Post
Jarod
post
Post #10





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


Analizuje ten przykład jeszcze raz i mam wrażenie, że autor troszke zamieszał. Czy metoda __get nie powinna raczej wyglądać tak:
  1. <?php
  2. function __get($propertyName) {
  3.  
  4. //Jeśli istnieje metoda to ją wywołujemy
  5. if (method_exists($this, 'get' , $propertyName))
  6. {
  7. return call_user_func(array($this, 'get' , $propertyName));
  8. }
  9. else
  10. {  //Jeśli nie istnieje to sprawdzamyczy podane propertyName jest w tablicy. A nie sp
    rawdzamy
  11. //tego na samym początku bo to bez sensu.. 
  12. if (!array_key_exists($propertyName, $this->propertyTable))
  13. throw new Exception('Błędna własność '.$propertyName.'!');
  14. else return $this->data[$this->propertyTable[$propertyName]];
  15. }
  16. }
  17. ?>


Po co sprawdzać czy istnieje propertyName przed sprawdzeniem istnienia metody? Po to się to sprawdza (chyba) czy można zwrócić wartość z tablicy propertyTable..?
Go to the top of the page
+Quote Post
Ludvik
post
Post #11





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Tak też może być. Autor klasy zakładał, że nawet w przypadku istnienia metody dostępowej, należy sprawdzić czy dane istnieją w tablicy. Nie ma danych - metoda nie ma sensu...

U Ciebie istnieje możliwość wywołania metod get* nawet w przypadku, gdy dane w tablicy nie istnieją...

Kod metody __set też mi się nie podoba...
Go to the top of the page
+Quote Post
Jarod
post
Post #12





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


Cytat(Ludvik @ 21.08.2006, 10:15 ) *
Tak też może być. Autor klasy zakładał, że nawet w przypadku istnienia metody dostępowej, należy sprawdzić czy dane istnieją w tablicy. Nie ma danych - metoda nie ma sensu...

Po co? Jak istnieje metoda to ją wykonujesz a nie pobierasz wartość z tablicy. Jak napiszesz
  1. <?php
  2. __get(Costam)
  3. ?>
to sprawdzane jest czy istniej metoda getCostam, jeśli tak ją wywołujesz a jeśli nie to to zwraca
  1. <?php
  2. $this->data[$this->propertyTable['Costam']]
  3. ?>



Cytat(Ludvik @ 21.08.2006, 10:15 ) *
U Ciebie istnieje możliwość wywołania metod get* nawet w przypadku, gdy dane w tablicy nie istnieją...


Jak wyżej.
Go to the top of the page
+Quote Post
Ludvik
post
Post #13





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Cytat
Po co? Jak istnieje metoda to ją wykonujesz a nie pobierasz wartość z tablicy.

Nie odpowiem na pytanie po co - bo nie jestem autorem tej klasy. Sam bym sprawdzał dopiero w przypadku braku metody dostępowej...
Go to the top of the page
+Quote Post
Jarod
post
Post #14





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


Cytat(Ludvik @ 21.08.2006, 16:57 ) *
Nie odpowiem na pytanie po co - bo nie jestem autorem tej klasy. Sam bym sprawdzał dopiero w przypadku braku metody dostępowej...


Ale sam napisałeś:
Cytat(Ludvik @ 21.08.2006, 10:15 ) *
U Ciebie istnieje możliwość wywołania metod get* nawet w przypadku, gdy dane w tablicy nie istnieją...


A to nieprawda - starałem się to wytłumaczyć w poscie wyżej.. :/
Go to the top of the page
+Quote Post
Ludvik
post
Post #15





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Mylisz się. Przeanalizuj dobrze kod. Żeby wywołać metodę get* musi być spełniony warunek (w którym masz błąd składniowy, o którym już wcześniej pisałem...):
  1. <?php
  2. if (method_exists($this, 'get' . $propertyName))
  3. ?>

Czyli musi istnieć odpowiednia metoda. Nie ma tutaj żadnego sprawdzenia, czy metoda odwołuje się do istniejącego pola. To zadanie zostało powierzone właśnie metodzie dostępowej, a nie __get... Tak na prawdę fakt posiadania przez klasę metody getDziwnePole nie gwarantuje w Twoim przypadku posiadania tego pola...
Go to the top of the page
+Quote Post
Jarod
post
Post #16





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


Cytat(Ludvik @ 21.08.2006, 18:12 ) *
Czyli musi istnieć odpowiednia metoda. Nie ma tutaj żadnego sprawdzenia, czy metoda odwołuje się do istniejącego pola. To zadanie zostało powierzone właśnie metodzie dostępowej, a nie __get...


Ok - zgadza się. Ale skąd wiesz, że metoda dostępowa tego nie sprawdza? Nie ma napisanego kodu metody dostępowej ale to chyba ona powinna sprawdzać i ewentualnie wyrzucić wyjątek.

Cytat(Ludvik @ 21.08.2006, 18:12 ) *
Tak na prawdę fakt posiadania przez klasę metody getDziwnePole nie gwarantuje w Twoim przypadku posiadania tego pola...


Masz racje. Ale to metoda getDziwnePole powinna sprawdzić czy jest takie pole i jeśli jest to się wykonać a jeśli nie to throw...

Moim zdaniem autor mota bardzo. Pozatym zaglębiając się bardziej w przykłady nie jestem przekonany czy tą książkę pisali experci..
Go to the top of the page
+Quote Post
Ludvik
post
Post #17





Grupa: Przyjaciele php.pl
Postów: 698
Pomógł: 3
Dołączył: 28.03.2004
Skąd: Wrocław

Ostrzeżenie: (0%)
-----


Cytat
Ok - zgadza się. Ale skąd wiesz, że metoda dostępowa tego nie sprawdza? Nie ma napisanego kodu metody dostępowej ale to chyba ona powinna sprawdzać i ewentualnie wyrzucić wyjątek.

Powinna, ale zbytnie zaufanie do programisty stwarza dodatkowe niebezpieczeństwo powstania błędów w kodzie. Co nie zmienia faktu, że ten błąd wyjdzie przy testach i jest raczej niegroźny, a wklepanie tego warunku spowoduje lekką stratę wydajności.
Go to the top of the page
+Quote Post
Jarod
post
Post #18





Grupa: Zarejestrowani
Postów: 1 190
Pomógł: 27
Dołączył: 23.04.2005

Ostrzeżenie: (0%)
-----


Cytat(Ludvik @ 21.08.2006, 18:46 ) *
(..)a wklepanie tego warunku spowoduje lekką stratę wydajności.


A waruenk przed sprawdzaniem nie wpływa na wydajność? Będzie to samo.. Chyba że się myle..


EDIT: Dręczy mnie ejszcze jedna sprawa na którą nie uzyskłame odpowiedzi.
Wydaje mi się, że błąd jest w metodzie validate(). Autor odwołuje suię w ten sposób
  1. <?php
  2. if ($this->address1) {
  3.  $this->errors['address1'] = 'Adres to pole wymagane';
  4.  }
  5. ?>


a powinno być chyba
  1. <?php
  2. if ($this->propertyTable['address1']) {
  3.  $this->errors['address1'] = 'Adres to pole wymagane';
  4.  }
  5. ?>


jeśli nie to dlaczego właśnie tak?

Ten post edytował J4r0d 21.08.2006, 22:23:15
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 14.09.2025 - 18:20