Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php5] $this w konstruktorze
Forum PHP.pl > Forum > PHP > Object-oriented programming
vaca
Witam!
Dopiero zaczynam swoją przygodę z PHP5 (a przy okazji także aktywnie z tym forum).
Sytuacja jest następująca: w konstruktorze obiektu wywoływana jest metoda (innej klasy), która załóżmy ma za zadanie ustawić jakieś początkowe wartości tworzonego obiektu. Jako jeden z jej argumentów przekazywana jest zmienna $this. Robię sobie var_dump na $this po wywołaniu tej metody - prawidłowo ustawia mi wartości zmiennych. Jednak próba odwołania się do konkretnej zmiennej daje nulla.. Da się to jakoś rozsądnie rozwiązać?
Mogę na przykładzie, jeśli piszę niedostatecznie jasno smile.gif
Cezar708
$this jeszcze na etapie konstruktora nie istnieje (bo właśnie jest tworzony), wyjściem z sytuacji są:

1. ręczne wykonanie metody już po stworzeniu obiektu:
  1. <?php
  2. $myObj = new className();
  3. $myObj->init(); // i tu wywołujesz wszystko i możesz odwołać się do $this
  4. ?>


2. w jakiś sposób wykorzystujesz metodę statyczną danej klasy lub zmienną statyczną:
  1. <?php
  2. $myObj = new className();
  3. className::StaticFunction($myObj);
  4. ?>


daj przykład co chcesz dokładnie zrobić to wtedy można sprecyzować co w danym momencie najlepiej wykorzystać...
vaca
Hmm..
Ok, to może na przykładzie:
CODE

<?php
class MojaKlasa {
var $zmienna;
function __construct() {
$o_init = new KlasaUstawiajaca(); // mamy klase, sluzaco do ustawiania poczatkowych wartosci
$o_init->setValues($this); // wywoluje metode, ktora ustawia wartosci
var_dump($this); // tu widac prawidlowo ustawione wartosci dla $zmienna
var_dump($this->zmienna); // tu $zmienna jest nullem
}
}
?>


Nie chcę wywoływać żadnej inicjującej metody stworzeniu obiektu (jak w rozwiązaniu 1.).
Bardzo nieeleganckie rozwiązanie jakie mi przyszło do głowy - przepisywanie wartości z $this na $this winksmiley.jpg Czyli coś jak:
CODE

function setObjectValues($o_object) {
foreach($o_object as $vc_var => $vm_value) {
$this->$vc_var = $vm_value;
}
}

Wstrętne, nie chcę tak, ale nie wiem jak inaczej..
zimi
może chodzi Ci o coś takiego?
  1. <?php
  2. class KlasaUstawiajaca{
  3. public $value;
  4. public function setValues($a){
  5. $a->zmienna = 'ble';
  6. }
  7. }
  8. class MojaKlasa {
  9. public $zmienna;
  10. public function __construct() {
  11. $o = new KlasaUstawiajaca();
  12. $o->setValues($this);
  13. }
  14. }
  15. var_dump(new MojaKlasa());
  16. ?>

to jest dziwny sposób inicjalizacji, nie wiem do czego coś takiego byłoby Ci potrzebne;
macvek
Ja zrobiłem to w ten sposób (można powiedzieć skopiowałem kod)
i u mnie var_dump w obu przypadkach wskazuje na integer
o wartości 2345 (czyli taki jaki jest inicjowany przez setValues)

  1. <?php
  2.  
  3. class KlasaUstawiajaca
  4. {
  5. function setValues($zmienna)
  6. {
  7. $zmienna->zmienna = 2345;
  8. }
  9. }
  10.  
  11. class MojaKlasa {
  12. var $zmienna;
  13. function __construct() 
  14. {
  15. $o_init = new KlasaUstawiajaca(); // mamy klase, sluzaco do ustawiania poczatkowych wartosci
  16. $o_init->setValues($this); // wywoluje metode, ktora ustawia wartosci
  17. var_dump($this); // tu widac prawidlowo ustawione wartosci dla $zmienna
  18. print ("<br>");
  19. var_dump($this->zmienna); // tu $zmienna jest nullem
  20. }
  21. }
  22.  
  23. $x = new MojaKlasa();
  24.  
  25. ?>


oczywiście u mnie stoi php 5
dr_bonzo
To prawdop. wina 4ki bo ona kopiuje obiekty zamiast przekazywac referencje do nich. Czyli

function setObjectVars( &$obj )
{
itp, uzywaj &
}
Sedziwoj
To w końcu PHP 4 czy 5?
Prph
Jezeli PHP 5 to obiekt przekazany jest przez referencje i nie powinny byc problemu. Ale nie o to chodzi. Przekazujesz referencje do obiektu, ktory nie jest jeszcze skonczony (przynajmniej mozna wziac to pod uwage). Jednak dziwny jest sposob inicjalizacji klasy. Glos moglby by zajac osoby dobrze znajace `przepisy` panujace w OOP. To mi troche wyglada na probe zrobienia czegos, co zalatwia dziedziczenie... Moze lepiej:

  1. <?php
  2. class Abstrakcyjna {
  3. protected $param1, param2;
  4.  
  5. public function __construct($param1) {
  6.  
  7. $this->param1 = $param1;
  8. $this->param2 = 'abcdef';
  9. }
  10. }
  11.  
  12. class Moja extends Abstrakcyjna {
  13. public function __construct() {
  14.  
  15. parent::_construct(1234);
  16.  
  17. //dalszy kod nowego konstruktora
  18. }
  19. }
  20. ?>
Sedziwoj
@Prph
Większości problemów typu, że nie da się czegoś ładnie zrobić w OOP, przyczyną jest złe projektowanie, czyli nie znajomość OOP...

Tu równie dobrze można zamiast przekazywać obiekt, pobierać wartości i je przypisywać, ale takie bezpośrednie odwołanie do innego obiektu mocno z nim łączy, co nie jest zbyt dobre.
Raczej powinno panować na tym forum zwyczaj, aby podawać co chcę zrobić, a potem jak próbowałem i nie działa, bo za często wychodzi błąd w tym jak chce się coś rozwiązać.
vaca
Z całą pewnością działam w php5. Swoją drogą ten kod działa w php4, oczywiście dodając referencje.
Może słowo 'inicjalizacja' nie było tu najlepsze, moim celem było uproszczenie przykładu. W rzeczywistości w tym miejscu (tzn. w KlasaUstawiajaca) dokonuje sie odserializowanie danych wyciągniętych z pewnego pliku. Zaserializowany jest cały obiekt klasy MojaKlasa (albo z niej dziedziczącej).
cicik
Cytat(Cezar708 @ 17.09.2007, 12:21:14 ) *
$this jeszcze na etapie konstruktora nie istnieje (bo właśnie jest tworzony), wyjściem z sytuacji są:

/.. ciach ../


eee... to ty nie inicjalizujesz składowych klasy w konstruktorze? Kurcze... a zawsze mnie uczono, że od tego on jest.
Mi tam w konstruktorze $this zawsze działa. Mogę odwołać się do pól w obiekcie. Ba! Nawet metode moge wywolac - prywatna,publiczna, chroniona - jaka chce! Ale może moje PHP jakieś dziwne jest.
Sedziwoj
@cicik
Gdy budujesz dom możesz stawiać w nim ściany, kłaść dach, ale do niego nie wprowadzasz rodziny, to robisz gdy już skończysz.

@vaca
Twój opis właściwie niewiele tłumaczy, nadal piszesz co robisz, nie co masz do zrobienia.
cicik
Cytat(Sedziwoj @ 18.09.2007, 18:15:33 ) *
@cicik
Gdy budujesz dom możesz stawiać w nim ściany, kłaść dach, ale do niego nie wprowadzasz rodziny, to robisz gdy już skończysz.


Kiepskie to porównanie. Od tego jest konstruktor żeby zainicjalizować obiekt.
Sedziwoj
Cytat(cicik @ 22.09.2007, 14:25:17 ) *
Kiepskie to porównanie. Od tego jest konstruktor żeby zainicjalizować obiekt.


Inicjalizujesz - budujesz, aby z niego potem korzystać - wprowadzić rodzinę.
Nie jest kiepski.
cicik
Cytat(Sedziwoj @ 22.09.2007, 14:55:08 ) *
Inicjalizujesz - budujesz, aby z niego potem korzystać - wprowadzić rodzinę.
Nie jest kiepski.


No i gdzie w swojej wypowiedzi widzisz różnice z tym co napisałem kilka postów wyżej?
Sedziwoj
Cytat(cicik @ 23.09.2007, 09:36:54 ) *
No i gdzie w swojej wypowiedzi widzisz różnice z tym co napisałem kilka postów wyżej?

Jak coś twierdzisz, dowódź.
cicik
Cytat(Sedziwoj @ 23.09.2007, 12:50:14 ) *
Jak coś twierdzisz, dowódź.


Jest prawie południe więc jestem wyspany. Ale mimo wszystko nie rozumiem.
Sedziwoj
Cytat(cicik @ 24.09.2007, 11:03:07 ) *
Jest prawie południe więc jestem wyspany. Ale mimo wszystko nie rozumiem.

Widzisz i nie pierwszy raz czegoś nie rozumiesz, a zapewne i nie ostatni.
Cezar708
Cytat(Cezar708 @ 17.09.2007, 10:21:14 ) *
$this jeszcze na etapie konstruktora nie istnieje (bo właśnie jest tworzony), wyjściem z sytuacji są:


Mea Culpa całkowicie się źle napisałem, chyba miałem zaćmienie jakieś w tym czasie.
Oczywiście obiekt istnieje i $this->value; musi działać,

Cytat(vaca @ 17.09.2007, 10:37:35 ) *
  1. <?php
  2. function setObjectValues($o_object) {
  3. foreach($o_object as $vc_var => $vm_value) {
  4. $this->$vc_var = $vm_value;
  5. } 
  6. }
  7. ?>


dlaczego nie... tylko, że trochę inaczej, jako prywatna składowa klasy:
  1. <?php
  2. class MyClass{
  3. function __construct($a_values){
  4. $this->setObjectValues($a_values);
  5. }
  6. private function setObjectValues($a_values) {
  7. foreach($a_values as $vc_var => $vm_value) {
  8. $this->$vc_var = $vm_value;
  9. } 
  10. }
  11. }
  12. ?>


nie uważam tego za złe rozwiązanie

PS: Sedziwoj i cicik nie kłóćsie się
zimi
może się wtrące smile.gif tylko mnie nie pobijcie smile.gif
na moje to @Sędziwojowi pod szyldem "wprowadzanie rodziny" chodzi o to że zmienna $this w konstruktorze jest używana jako parametr zewnętrznej funkcji, która ma ustawiać pola obiektu danego w tym parametrze (co wg @Sędziwoja ma prawo nie działać bądź jest niepoprawne, tak mi się wydaję...) co ma miejsce w kodzie @vaca
a @cicikowi zawsze $this w konstruktorze działa czy "buduję dom" czy "wprowadza rodzinę" (a przynajmniej tak można zrozumieć z jego postu gdzie piszę że $this zawsze mu działa, a nie zwraca uwagi na prawdopodobnie złe rozwiązanie projektowe jakie zostało przedstawione)
a jak się mylę to o co wy się kłócicie? O.o biggrin.gif:P
cicik
Cytat(zimi @ 24.09.2007, 12:02:40 ) *
a @cicikowi zawsze $this w konstruktorze działa czy "buduję dom" czy "wprowadza rodzinę" (a przynajmniej tak można zrozumieć z jego postu gdzie piszę że $this zawsze mu działa, a nie zwraca uwagi na prawdopodobnie złe rozwiązanie projektowe jakie zostało przedstawione)
a jak się mylę to o co wy się kłócicie? O.o biggrin.gif:P


Źle mnie zrozumiałeś. Zwróciłem uwagę na to, że $this w konstruktorze ZAWSZE działa.
Natomiast ciągle uparcie twierdzę, że konstruktor służy do zainicjalizowania obiektu. I DO NICZEGO WIĘCEJ (bo zimi próbuje mi wcisnąć, że twierdzę co innego). Bynajmniej w swoich projektach nie używam konstruktora do wykonywania bardziej złożonych operacji niż zainicjalizowanie zmiennych, stworzenie niezbędnych do działania obiektów innych klas etc. Do tego ZAWSZE się używa konstruktora - PO TO ON JEST!
envp
a może waca pokaże pełne kody obydwu klas ? bo coś mi tu śmierdzi smile.gif
zimi
Cytat
Źle mnie zrozumiałeś.

Cytat
(a przynajmniej tak można zrozumieć z jego postu gdzie piszę że $this zawsze mu działa, a nie zwraca uwagi [tu powinno być dopisane: "w tym poście"] na prawdopodobnie złe rozwiązanie projektowe jakie zostało przedstawione)

nie napisałem co ja rozumiem tylko co można zrozumieć...
dobrze Ciebie zrozumiałem, widzę jakie jest Twoje stanowisko, ale wydaję mi się że z tego wynikła kłótnia że powiedziałeś że działa zawsze (zgadzam się), ale nie napisałeś że to jest zły sposób (napisałeś, że konstruktor jest tylko do inicjalizacji dopiero teraz, przynajmniej w tym topicu smile.gif )

a jeśli nie jest tak jak mówię moglibyście wytłumaczyć powód swojej kłótni aby miała znamiona konstruktywnej smile.gif bo póki co to wygląda na przepychanki smile.gif
Sedziwoj
@Cezar708
Wiesz ale ograniczasz się do funkcji budowanego obiektu, chodzi o to żeby nie próbować przekazać tego co jeszcze budujesz do innych obiektów, można z innych korzystać, ale nie przekazać czegoś co jeszcze nie jest ukończone. Tworzenie osobnych metod do inicjalizacji, kiedy jest więcej kodu, jest dobre bo widać co sie dzieje w konstruktorze, ale przekazywanie obiektu (który jeszcze nie jest do końca utworzony, bo po to jest konstruktor aby przygotować go do użytku) jest złe.
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.