Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: metody i zmienne statyczne
Forum PHP.pl > Forum > PHP > Object-oriented programming
bliitz
Witam

Fragment przykładowej klasy:
  1. class Parse_Data
  2. {
  3. public $data = array();
  4. /**
  5.   * Create an instance of Parse_Data
  6.   *
  7.   * @staticvar empty $instance
  8.   * @return object
  9.   */
  10. public static function instance()
  11. {
  12. static $instance;
  13. empty( $instance ) AND $instance = new Parse_Data;
  14. return $instance;
  15. }
  16. /**
  17.   *
  18.   * @param array $post
  19.   * @param array $data
  20.   * @return boolean
  21.   */
  22. public function check( $post, array $data )
  23. {
  24. $this->data = new Validation( $post );
  25. $this->data->pre_filter( 'trim' );
  26. foreach( $data as $k => $v )
  27. {
  28. $this->data->add_rules( $k, $v );
  29. }
  30. return $this->data->validate();
  31. }
  32. }


i sposób w jaki chcę jej użyć:
  1. if( Parse_Data::check( $_POST, array( 'art_title' => 'required',
  2. 'art_content' => 'required',
  3. 'art_teen' => 'numeric' ) ) )


i teraz kilka pytań:
1. Dlaczego nie zwraca to błędu mimo iż check() nie jest statyczna?
2. W jaki sposób mogę dostać się do zmiennej $data z zewnątrz czyli coś w ten deseń Parse_Data::instance()->data ? ( oczywiście to nie działa tylko dlaczego )
3. Czy jedyny sposób do utworzenie zmiennej $data jako statycznej i odwołanie się do niej w postaci Parse_Data::$data czy pozostawienie jej zwykłą ( nie statyczną ) i utworzenie metody dzięki której będzie do niej dostęp ?
blooregard
Cytat
1. Dlaczego nie zwraca to błędu mimo iż check() nie jest statyczna?

Dlatego, że takie odwołanie do metody klasy (publicznej) jest również składniowo poprawne, mimo, iż nie jest ona metodą statyczną.
Natomiast na pewno zwraca Ci błąd w tym miejscu:
  1. $this->data = new Validation( $post );
  2. $this->data->pre_filter( 'trim' );

a czemu, wyjaśniam Ci poniżej.

Cytat
2. W jaki sposób mogę dostać się do zmiennej $data z zewnątrz czyli coś w ten deseń Parse_Data::instance()->data ? ( oczywiście to nie działa tylko dlaczego )

Podany przez Ciebie sposób nie zadziała z prostej przyczyny: -> to operator dostępu do składowej z obiektu klasy, a Ty wywołujesz po prostu metodę klasy bez tworzenia obiektu. Więc zaprezentowany przez Ciebie przykład jest totalnie pozbawiony sensu: Parse_Data::instance() nie jest obiektem, lecz odwołaniem do metody instance() w klasie Parse_Data.

Cytat
3. Czy jedyny sposób do utworzenie zmiennej $data jako statycznej i odwołanie się do niej w postaci Parse_Data::$data czy pozostawienie jej zwykłą ( nie statyczną ) i utworzenie metody dzięki której będzie do niej dostęp ?

Jedyny sposób to:
  1. static $data
  2. print_r Parse_Data::data;

Nie zwrócisz składowej niestatycznej jako wyniku wywołania metody (czyli return $this->skladowa;), bo wywali Ci parse errora, że używasz $this na czymś, co nie jest obiektem, a tak by się stało w tym przypadku:
  1. <?php
  2.  
  3. class Parse_Data
  4. {
  5. public $data = array('1' , '2');
  6.  
  7. public function getData($var_name) {
  8. return $this->$var_name;
  9. }
  10. }
  11.  
  12.  
  13.  
  14. $a = Parse_Data::getData('data');
  15.  

rezultat:
Fatal error: Using $this when not in object context in /var/www/test/index.php on line 8
bliitz
To sporo mi wyjaśniło rolleyes.gif
przekształcenie metody w następujący sposób sprawia, że jest ok
  1. public function check( $post, array $data )
  2. {
  3. self::$data = new Validation( $post );
  4. self::$data->pre_filter( 'trim' );
  5. foreach( $data as $k => $v )
  6. {
  7. self::$data->add_rules( $k, $v );
  8. }
  9. return self::$data->validate();
  10. }

z tym że wydaje mi się trochę dziwny ( dziwnie wygląda to self tongue.gif ) wiem że to jest sposób aby odwoływać się to zmiennych statycznych ale czy to jest właściwy sposób rozwiązania tego problemu?
blooregard
No raczej tak, tylko może zrób z tego normalną metodę statyczną, zadeklaruj $data jako static, no i odwołuj się do niej self::$data w każdym odwołaniu. A generalnie mam pytanie: nie da się tej klasy Parse_Data tak napisać, żeby utworzyć normalny jej obiekt i móc do jej metod odwoływać się poprzez $Parse_Data_Object->metoda() ?
bliitz
Hmm metoda tej klasy jest wywoływana wiele razy w różnych plikach. Uznałem, że lepiej zrobić ją statyczną niż za każdym razem tworzyć jej obiekt. Chyba, że jest inny sposób na taki przypadek niż metody statyczne?
blooregard
Cytat
Uznałem, że lepiej zrobić ją statyczną niż za każdym razem tworzyć jej obiekt.

W takim razie zrób z Parse_Date singletona. Obiekt utworzysz raz, a będziesz mógł sobie używać normalnych metod wszędzie, gdzie będzie to potrzebne.
bliitz
a czy właśnie metoda instance() nie jest singletonem?
i odwoływanie się w taki sposób Parse_Data::instance()->check(); przykładowo?
zegarek84
nie jest singeltonem: Wzorce projektowe - singleton - niżej masz inne dosyć dobrze opisane...
zrób tak jak radzi Blooregard,

lub całkiem inaczej bez singeltona: jeśli masz problem z zasięgiem to weź na uwagę, że przypisując dalej już utworzoną klasę nie kopiujesz jej domyślnie a domyślnie w php5 przekazujesz referencję do niej... tak więc:
$a=new klasa();
$b=$a;// i tu jest przekazana referencja - w php4 to tak jak z zmiennymi $b=&$a;

więc jeśli przekażesz klasę jako parametr funkcji przekażesz referencję do niej...
jeśli w jakimś konstruktorze bądź metodzie przypiszesz klasę do zmiennej prywatnej, publicznej (i na upartego statycznej) to masz też odwołanie przez referencję z wewnątrz tej klasy... więc jeśli chcesz mieć tą samą klasę w innych klasach, ale tą samą instancję to utwórz tą instancję klasy przed tworzeniem następnych i przekaż ją konstruktorowi bądź przypisz ją przez jakąś metodę - nie twórz instancji wtedy klasy w konstruktorze przez new - chyba, że chcesz mieć nową instancję - nie zależny inny obiekt... jeszcze poczytaj o niuansie private i protected - zwłaszcza jesli będziesz miał rozszerzać klasy...

function cos($x){$x->metoda();};
//użycie:
cos($a); //itd...

w manualu:
Objects and references
bliitz
po przeczytaniu wyżej podlinkowanego arta zmodyfikowałem nieco i teraz jest:
  1. class Parse_Data
  2. {
  3. public static $data = array();
  4. private static $_instance = null;
  5.  
  6. private function __construct(){}
  7. /**
  8.   * Create an instance of Parse_Data
  9.   *
  10.   * @return object
  11.   */
  12. public static function instance()
  13. {
  14. if( is_null( self::$_instance ) )
  15. {
  16. self::$_instance = new Parse_Data();
  17. }
  18. return self::$_instance;
  19. }
  20. /**
  21.   *
  22.   * @param array $post
  23.   * @param array $data
  24.   * @return boolean
  25.   */
  26. public function check( $post, array $data )
  27. {
  28. self::$data = new Validation( $post );
  29. self::$data->pre_filter( 'trim' );
  30. foreach( $data as $k => $v )
  31. {
  32. self::$data->add_rules( $k, $v );
  33. }
  34. return self::$data->validate();
  35. }
  36. }


na moje oko ( niezbyt jeszcze wprawione tongue.gif ) wydaję się ok i spełnia swoje zadanie.
Co do drugiego sposobu to nie chcę ładować tworzenia instancji klasy do nadrzędnego konstruktora bo nie będzie ona na każdej podstronie wykorzystywana, więc singleton wydaje mi się lepszym rozwiązaniem.
zegarek84
ok - ale drobny szczegół - jak już tak zrobiłeś to w metodzie check mogłeś zamiast self użyć $this i zmienna $data nie musi być statyczna ;p
bliitz
i tak tez zrobiłem tongue.gif
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.