Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Odniesienie się do obiektu przez inny w nim powstały
Forum PHP.pl > Forum > PHP > Object-oriented programming
l0ud
Witam. Właśnie sobie uświadomiłem że dopiero raczkuję w programowaniu obiektowym, bo nie wiem nawet czy to jest możliwe: mam zamiar odnieść się do $zmienna znajdującej się w $obiekta w innym utworzonym przez niego obiekcie.

  1. <?php
  2. class A {
  3.  
  4. public $zmienna;
  5.  
  6. public function __construct() {
  7. $this->zmienna = asd;
  8. $obiektb = new B;
  9. }
  10.  
  11. }
  12.  
  13. class B {
  14.  
  15. public function __construct() {
  16. //czy da się teraz odnieść do $zmienna w obiekta?
  17. }
  18.  
  19. }
  20.  
  21. $obiekta = new A;
  22. ?>


Czy to jest w ogóle możliwe? wstydnis.gif

Pozdrawiam
Cysiaczek
Nie, ale możesz przekazać referencję obiektu A do obiektu B i wtedy się da smile.gif

Pozdrawiam.
pyro
Cytat(l0ud @ 29.03.2008, 21:27:22 ) *
Witam. Właśnie sobie uświadomiłem że dopiero raczkuję w programowaniu obiektowym, bo nie wiem nawet czy to jest możliwe: mam zamiar odnieść się do $zmienna znajdującej się w $obiekta w innym utworzonym przez niego obiekcie.

  1. <?php
  2. class A {
  3.  
  4. public $zmienna;
  5.  
  6. public function __construct() {
  7. $this->zmienna = asd;
  8. $obiektb = new B;
  9. }
  10.  
  11. }
  12.  
  13. class B {
  14.  
  15. public function __construct() {
  16. //czy da się teraz odnieść do $zmienna w obiekta?
  17. }
  18.  
  19. }
  20.  
  21. $obiekta = new A;
  22. ?>


Czy to jest w ogóle możliwe? wstydnis.gif

Pozdrawiam


Rozwiązanie twojego problemu jest aż za proste tongue.gif

class B extends A
l0ud
Rozumiem, że masz na myśli coś takiego?

  1. <?php
  2. class A {
  3.  
  4. public $zmienna;
  5.  
  6. public function __construct() {
  7. $this->zmienna = asd;
  8. $obiektb = new B(&$this);
  9. }
  10.  
  11. }
  12.  
  13. class B {
  14.  
  15. public function __construct(&$parent) {
  16. echo $parent->zmienna;
  17. }
  18.  
  19. }
  20.  
  21. $obiekta = new A;
  22. ?>


Zaczynam się zastanawiać, czy jest to dobre rozwiązanie przy większej aplikacji. Przykład powyżej był uproszczony: w rzeczywistości mam obiekt inicjujący, który wczytuje inne, tworzy i dodaje do swoich zmiennych (uciekło mi właściwe słowo). Te wczytane obiekty powinny móc się do siebie odnosić i dotychczas myślałem że będzie to możliwe bez problemów przez obiekt rodzica (inicjujący). Teraz się zastanawiam, czy przekazując za każdym razem jego instancję nie dochodzę do jakiegoś antywzorca?
Moli
Możesz dać np.
  1. <?php
  2. $this->var = new var ( ) ;
  3. ?>

i później
  1. <?php
  2. $this->var->metoZklasyVar( );
  3. ?>
pyro
Cytat(l0ud @ 29.03.2008, 21:51:55 ) *
Rozumiem, że masz na myśli coś takiego?

  1. <?php
  2. class A {
  3.  
  4. public $zmienna;
  5.  
  6. public function __construct() {
  7. $this->zmienna = asd;
  8. $obiektb = new B(&$this);
  9. }
  10.  
  11. }
  12.  
  13. class B {
  14.  
  15. public function __construct(&$parent) {
  16. echo $parent->zmienna;
  17. }
  18.  
  19. }
  20.  
  21. $obiekta = new A;
  22. ?>


Zaczynam się zastanawiać, czy jest to dobre rozwiązanie przy większej aplikacji. Przykład powyżej był uproszczony: w rzeczywistości mam obiekt inicjujący, który wczytuje inne, tworzy i dodaje do swoich zmiennych (uciekło mi właściwe słowo). Te wczytane obiekty powinny móc się do siebie odnosić i dotychczas myślałem że będzie to możliwe bez problemów przez obiekt rodzica (inicjujący). Teraz się zastanawiam, czy przekazując za każdym razem jego instancję nie dochodzę do jakiegoś antywzorca?


nie...
l0ud
@pyro, nie wiem do czego Twoja odpowiedź się odnosi, bo w cytacie znajdują się 3 pytania.

@Moli, nie zrozumiałem tego zbytnio. Chodzi mi o odniesienie się w podrzędnym obiekcie do nadrzędnego, a nie odwrotnie.
Moli
No to jak dasz
  1. <?php
  2. class B extends A
  3. ?>

To do metod z A dajesz
  1. <?php
  2. $this->metodaZklasyA();
  3. ?>
l0ud
@Moli, ale ja chcę się odnieść do konkretnego obiektu zawierającego swoje zmienne i dane a nie tylko odziedziczyć jego metody smile.gif No chyba że coś źle myślę?
pyro
Cytat(l0ud @ 29.03.2008, 22:37:49 ) *
@Moli, ale ja chcę się odnieść do konkretnego obiektu zawierającego swoje zmienne i dane a nie tylko odziedziczyć jego metody smile.gif No chyba że coś źle myślę?


dziedziczysz tez zmienne i inne dane od rodzica
l0ud
Cytat
dziedziczysz tez zmienne i inne dane od rodzica


Ale nie konkretnego. (albo jestem ciągle w błędzie). Przykład: jest obiekt $db a po nim dziedziczy $queryMaker . Dane do bazy dla $db podajemy w konstruktorze. Teraz chcemy w $queryMaker wykonać zapytanie do bazy wykorzystując obiekt $db, który został już utworzony. Chyba nie uda się to przy użyciu dziedziczenia? smile.gif Singleton nie wchodzi w grę.
Kicok
Dlaczego miałoby się nie udać?
  1. <?php
  2.  
  3.  
  4. class DB
  5. {
  6. public $connected = false;
  7. protected $prefix = 'abc_';
  8.  
  9.  
  10. public function __construct( )
  11. {
  12. echo "Połączono z bazą danych<br />";
  13. $this->connected = true;
  14.  
  15. }
  16.  
  17. public function query( $query )
  18. {
  19. echo "Wykonujesz zapytanie:<pre>$query</pre><br />";
  20. }
  21.  
  22. }
  23.  
  24.  
  25. class QueryMaker extends DB
  26. {
  27.  
  28. public function makeSelect( $table, $cols = '*' )
  29. {
  30. if( $this->connected )
  31. {
  32. echo "OK, jesteś połączony<br />";
  33.  
  34. $query = "SELECT $cols FROM {$this->prefix}{$table}";
  35. $this->query( $query );
  36. }
  37.  
  38. }
  39.  
  40. }
  41.  
  42.  
  43. $query = new QueryMaker();
  44. $query->makeSelect( 'tabela' );
  45.  
  46. $query->makeSelect( 'tabela2', 'a, b, c' );
  47.  
  48. ?>


Różnica jest taka, że tworzymy tylko obiekt klasy QueryMaker. Jako że klasa ta nie ma swojego konstruktora to wywoływany jest konstruktor rodzica i nawiązywane jest połączenie z bazą danych. Takie rozwiązanie ma jednak sporo wad, np.: nie da się teraz sensownie przekazać parametrów połączenia z bazą - musiałbyś przerobić klasę DB na statyczną. Trzeba także zrobić z QueryMakera Singleton bo każda nowa instancja będzie nawiązywała nowe połączenie z bazą danych.

Ja proponowałbym coś takiego:
  1. <?php
  2.  
  3.  
  4. class DBConfig
  5. {
  6. public static $DBhost  = 'localhost';
  7. public static $DBuser  = 'root';
  8. public static $DBpass  = '';
  9. public static $DBname  = 'test';
  10. public static $DBprefix = '';
  11.  
  12. public static function setConfig( array $configValues )
  13. {
  14. self::$DBhost  = $configValues['host'];
  15. self::$DBuser  = $configValues['user'];
  16. self::$DBpass  = $configValues['pass'];
  17. self::$DBname  = $configValues['name'];
  18. self::$DBprefix = $configValues['prefix'];
  19. }
  20. }
  21.  
  22.  
  23.  
  24. class DB
  25. {
  26. private $connID = null;
  27.  
  28.  
  29. public function __construct()
  30. {
  31. echo "Następuje połączenie z serwerem '" . DBConfig::$DBuser . ":" . DBConfig::$DBpass ."@" . DBConfig::$DBhost . "' i wybranie bazy '" . DBConfig::$DBname . "'<br />";
  32. }
  33.  
  34. public function __destruct()
  35. {
  36. echo "Koniec połączenia z serwerem<br />";
  37. }
  38.  
  39.  
  40. public function query( Query $query )
  41. {
  42. echo "Wykonuje zapytanie:<pre>$query</pre><br />";
  43. }
  44.  
  45. }
  46.  
  47.  
  48.  
  49. interface Query
  50. {
  51. public function __toString();
  52. }
  53.  
  54.  
  55.  
  56. class Select implements Query
  57. {
  58. private $queryParts = array();
  59.  
  60.  
  61. public function __construct( $table, array $cols = array() )
  62. {
  63. $this->queryParts['cols'] = empty( $cols ) ? '*' : implode( ', ', $cols );
  64. $this->queryParts['table'] = $table;
  65. }
  66.  
  67.  
  68. public function where( $where )
  69. {
  70. $this->queryParts['where'] = $where;
  71. return $this;
  72. }
  73.  
  74. public function order( $order, $direction = 'ASC' )
  75. {
  76. $this->queryParts['order'][] = "$order $direction";
  77. return $this;
  78. }
  79.  
  80. public function limit( $a, $b = null )
  81. {
  82. $this->queryParts['limit'] = is_null( $b ) ? "$a" : "$a, $b";
  83. return $this;
  84. }
  85.  
  86.  
  87. public function __toString()
  88. {
  89. $query = "SELECT {$this->queryParts['cols']}\nFROM " . DBConfig::$DBprefix . "{$this->queryParts['table']}";
  90.  
  91. if( !empty( $this->queryParts['where'] ) ) {
  92. $query .= "\nWHERE ( {$this->queryParts['where']} )";
  93. }
  94. if( !empty( $this->queryParts['order'] ) ) {
  95. $query .= "\nORDER BY " . implode( ', ', $this->queryParts['order'] );
  96. }
  97. if( !empty( $this->queryParts['limit'] ) ) {
  98. $query .= "\nLIMIT {$this->queryParts['limit']}";
  99. }
  100.  
  101.  
  102. return $query;
  103. }
  104.  
  105. }
  106.  
  107.  
  108. class Update implements Query
  109. {
  110. // ...
  111.  
  112. public function __toString()
  113. {
  114. }
  115.  
  116. }
  117.  
  118. class Insert implements Query
  119. {
  120. // ...
  121.  
  122. public function __toString()
  123. {
  124. }
  125.  
  126. }
  127.  
  128.  
  129.  
  130.  
  131. $DBconfig = array(
  132. 'host'  => 'localhost',
  133. 'user'  => 'root',
  134. 'pass'  => 'pass',
  135. 'name'  => 'baza',
  136. 'prefix' => 'abc_'
  137. );
  138. DBConfig::setConfig( $DBconfig );
  139.  
  140.  
  141.  
  142. $DB = new DB;
  143.  
  144.  
  145. $query = new Select( 'tabela', array( 'col1', 'col2', 'col3' ) );
  146. $DB->query( $query );
  147.  
  148. $query = new Select( 'tabela' );
  149. $query->where( 'col1 = 'abcde' AND ( col2 = 321 OR col3 IN ( 0, 2, 4, 6, 8 ) )' )
  150. ->order( 'col1' )
  151. ->order( 'col3', 'DESC' )
  152. ->limit( 50, 25 );
  153. $DB->query( $query );
  154.  
  155. ?>


Warto też poczytać o:
Criteria
http://www.php.net/manual/pl/language.oop5.static.php
http://www.php.net/manual/pl/language.oop5...nekudotayim.php
http://www.php.net/manual/pl/language.oop5.interfaces.php
http://www.php.net/manual/pl/language.oop5.typehinting.php
pyro
Cytat(l0ud @ 30.03.2008, 00:10:12 ) *
Ale nie konkretnego. (albo jestem ciągle w błędzie). Przykład: jest obiekt $db a po nim dziedziczy $queryMaker . Dane do bazy dla $db podajemy w konstruktorze. Teraz chcemy w $queryMaker wykonać zapytanie do bazy wykorzystując obiekt $db, który został już utworzony. Chyba nie uda się to przy użyciu dziedziczenia? smile.gif Singleton nie wchodzi w grę.


jakto nie konkretnego? DZIEDZICZYSZ DANE KONKRETNEGO DZIEDZICZONEGO RODZICA, czyli tego, którego podasz w paramtetrze extends
l0ud
Kicok, dzięki wielkie Twoja odpowiedź na pewno mi się przyda przy budowie sterownika bazy winksmiley.jpg Tak czy siak wróciliśmy właściwie do punktu wyjścia, czyli przekazania $DB do dowolnej klasy. Owszem, można by to było robić za każdym razem przez np. parametr w konstruktorze, ale licząc, że podobnych klas do przekazania może być kilkanaście, byłoby to niepraktyczne. Do singletonów się nie przekonam, więc myślałem jak to objeść.

Wymyśliłem utworzenie głównego obiektu $fbCore, który będzie tworzył i przechowywał wszystkie inne, przekazując im przy tworzeniu swoją instancję. Wtedy taka dołączona klasa miałaby możliwość np. do odniesienia się do wcześniej zadeklarowanej klasy bazy danych w ten sposób:
(przykładowy fragment):

  1. <?php
  2. class configRegistry {
  3. private $db;
  4. private $configArray;
  5.  
  6. public function __construct(fbCore $fbCore) {
  7. $this->db = $fbCore->getObject('database');
  8. $this->loadConfig();
  9. }
  10. ?>


Po czym inne obiekty mogłyby się odnieść do configRegistry przez $fbCore->getObject('configRegistry') smile.gif (z założenia prawie wszystkie obiekty byłyby tworzone od razu po zaincludowaniu ich kodu przez $dbCore. Byłaby też możliwość np. załadowania odpowiedniego modelu w klasie widoku przez $modelInstance = $fbCore->loadModel('nazwa_pliku','nazwaKlasy')

Główny problem, to czy nie dochodzimy w takiej koncepcji do jakiegoś antywzorca? sad.gif

Pozdrawiam
Cysiaczek
Przenoszę na OOP

Nie będzie to jakiś antywzorzec, a przynajmniej ja tego problemu nie widzę. Możesz opisać, dlaczego tak uważasz?
l0ud
Bo za każdym razem przekazujemy wszystko do wszystkiego, czyli do każdego wczytanego obiektu przekazujemy instancję $dbCore które zawiera instancje do wszystkich innych klas. Chociaż tak po przemyśleniu, chyba nie jest to aż tak strasznie zasobożerne? Druga sprawa, że od razu zakładamy że każdy wczytany obiekt musi pobierać w konstruktorze tylko instancję $dbcore. Chociaż to chyba również nie jest takie złe, bo mamy jeden interfejs do tego i porządek? smile.gif

Generalnie w powyższym poście chodziło mi o ocenę pomysłu przez osobę bardziej doświadczoną z OOP. Nie chciałbym popełnić poważnych błędów już na starcie tworzenia rozbudowanej aplikacji.

Pozdrawiam
Cysiaczek
Pamiętaj, że przechowujesz tylko referencje do obiektów, więc nie jest to coś strasznego. Należy jedynie uważać z kopiami obiektów smile.gif

Pozdrawiam
l0ud
Problemów z kopiami raczej nie będzie, bo klasa jest includowana i obiekt z niej tworzony tylko raz, przez użycie $fbCore->loadX() . Za każdym każdym razem gdy jest potrzebny, pobieram instancję przez $dbCore->getObject() . Myślę, że to dobra metoda pod warunkiem, że uwzględni się wyjątki takie jak np. klasy abstrakcyjne.
Tak więc problem rozwiązany smile.gif

Dzięki za pomoc
Pozdrawiam
Sedziwoj
Nie wiem dlaczego, ale w trakcie czytania na myśl nasunęły mi się dwa wzorce, Budowniczy i Obserwator...
(ale zmęczony jestem, więc nie analizuję tego dokładniej, muszę w końcu wypocząć... ach ten remont)

Cytat(Cysiaczek @ 30.03.2008, 15:57:32 ) *
Pamiętaj, że przechowujesz tylko referencje do obiektów, więc nie jest to coś strasznego. Należy jedynie uważać z kopiami obiektów smile.gif


Dlatego w PHP5 domyślnie jest przy przypisaniu referencja robiona. (można wywalić & jak używasz PHP5 [a masz public więc na pewno tak jest])
Do tego kopiowanie jest ciężkie jak są złożone zależności.

Tak myśląc jednak trochę, to Budowniczy trochę jest innego zastosowania... Ale jeśli te wartości się nie zmieniają, to ustawienie ich jest najlepszym rozwiązaniem. Natomiast jeśli są zmienne to można chyba użyć obserwatora, ale to jeśli jest potrzeba reakcji na zmianę...

W sumie to coś mi się wydaje, że można by było te wartości przekazać tamtemu budowanemu obiektowi, ale musiał bym się wczytać.

(I jak już wiele razy pisałem, nie przedstawiajcie swoich rozwiązań, przemyśleń, a to co macie zrobić. Mówię tak bo to problem jest do rozwiązania, a wielokrotnie już się zdarzało, że autor proponując rozwiązanie nie przedstawił tego dobrze. Tak więc piszcie co jest problemem, a potem co najwyżej swoją propozycję, bo jak nie wiemy co dokładnie mamy rozwiązać, ciężko coś doradzić. Tak jak czy to się zmienia, czy obiekty muszą wiedzieć o zmianie itp. itd, a niże w ogóle inaczej to rozwiązać? Dlatego dobry opis problemu jest tak ważny)
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.