Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Singleton
Forum PHP.pl > Forum > PHP
Aztech
To zacznijmy od początku.
Mam sobie taką klasę bazową (zostawiam najważniejsze elementy)
  1. <?php
  2.  
  3. /**
  4.  * @author Tomasz Suchanek
  5.  * @copyright Tomasz Suchanek 
  6.  * @final 
  7.  */
  8.  
  9. require_once('config.inc.php');
  10. require_once('$RBX_CORE/includes/errors.inc.php');
  11. require_once('$RBX_CORE/includes/constant.inc.php');
  12.  
  13. /**
  14.  * Klasa bazowa dla wszystkich klas
  15.  *
  16.  */
  17. abstract class BaseClass {
  18.  
  19. /**
  20.    * Połaczenie z bazą danych
  21.    *
  22.    * @var array Przechowuje identyfiaktor połączenia z bazą danych.
  23.    * @access private
  24.    */
  25. private $db;
  26.  
  27. /**
  28.    * Wynik zapytania
  29.    *
  30.    * @var array Wynik zapytania skierowanego do bazy
  31.    * @access private  
  32.    */
  33. private $result;
  34.  
  35. /**
  36.    * Zapytanie do bazy
  37.    *
  38.    * @var string Zapytanie kierowane do bazy
  39.    * @access private
  40.    */
  41. private $sql;
  42.  
  43. /**
  44.    * Konstruktor
  45.    * @access public
  46.    */
  47. public function __construct(){
  48.  
  49. global $RBX_DB;
  50.  
  51. # połącz z bazą typu MySQL
  52. $this->db = new PDO('mysql:host='.$RBX_DB['host'].';dbname='.$RBX_DB['name'], $RBX_DB['user'], $RBX_DB['pass']);
  53.  
  54. #polskie litery
  55. $this->setSql('SET NAMES latin2;
  56. SET collation_connection = latin2_general_ci;');
  57. $this->doSQL();
  58.  
  59. # raportuj wszystkie błędy z PDO
  60. $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  61.  
  62. # raportuj wszysrkie błedy z php
  63.  
  64. }
  65.  
  66. /**
  67.    * Ustawia wartości domyślne dla pól prywatnych klasy
  68.    * 
  69.    * @abstract 
  70.    *
  71.    */
  72. abstract public function setDefault();
  73.  
  74. /**
  75.    * Zwróc obiekt połączenia z bazą
  76.    *
  77.    * @return array Tablica z identyfiaktorem połączenia z bazą danych
  78.    * @access public
  79.    */  
  80. public function getDB(){
  81. return $this->db;
  82. }
  83.  
  84. /**
  85.    * Zwraca rezultat zapytania
  86.    *
  87.    * @return array Tablica zawierająca rezultat zapytania
  88.    * @access public
  89.    */
  90. public function getResult(){
  91. return $this->result;
  92. }
  93.  
  94. /**
  95.    * Ustaw zapytanie sql
  96.    *
  97.    * @param string $sql Zapytanie SQL
  98.    * @access public  
  99.    */
  100. public function setSql($sql) {
  101. $this->sql = $sql;
  102. }
  103.  
  104. /**
  105.    * Zwróć treść zapytania
  106.    *  
  107.    * @return string $sql Zapytanie SQL
  108.    */
  109. public function getSql() {
  110. return $this->sql;
  111. }
  112.  
  113. /**
  114.    * Zwróć wyjątek jeśli rezultat zapytania jest pusty
  115.    * 
  116.    * @return true jeśli wynik zapytania jest poprawny
  117.    * @access public
  118.    */
  119. public function checkResult() {
  120. if ($this->result) {
  121. return true;
  122. }
  123. else {
  124. return false;
  125. }
  126. }
  127.  
  128. /**
  129.  * Wywołanie wszytkich metod związanych z wykonaniem zapytanie w jednej funkcji
  130.    * treść zapytania zostaje zapamiętana
  131.    *
  132.    * @param string $sql Zapytanie SQL
  133.    * @access public
  134.    * @return boolean
  135.    */
  136. public function doSQL($sql=''){
  137.  
  138. # gdy niepusty to zapisz zapytanie SQL
  139. if (!empty($sql)) $this->setSql($sql);
  140.  
  141. #wykonaj zapytanie i zapisz do wyników
  142. $stmt = $this->db->prepare($this->getSql());
  143. $stmt->execute();
  144. $this->result = $stmt->fetchAll(PDO::FETCH_ASSOC);
  145. if (isset($this->result[0])) {
  146.  $this->result = $this->result[0];
  147.  } 
  148. $stmt->closeCursor();  
  149. return $this->checkResult();
  150. }
  151. }
  152.  
  153. ?>

i chciałem skorzystać z wzorca Singleton (osatnio czytałem i postanowiłem przerobić to tak, żeby działało)
Więc zrobiłem tak:
$db jest statyczne
  1. <?php
  2. private static $db = false;
  3. ?>

getDB zmieniłem żeby działało jak getIsntance
  1. <?php
  2. public function getDB(){
  3. global $RBX_DB;
  4. if (self::$db == false) {
  5. self::$db = new PDO('mysql:host='.$RBX_DB['host'].';dbname='.$RBX_DB['name'], $RBX_DB['user'], $RBX_DB['pass']);
  6. #polskie litery
  7. $this->doSQL("SET NAMES latin2; SET collation_connection = latin2_general_ci;");
  8. # raportuj wszystkie błędy z PDO
  9. $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  10. }
  11. return self::$db;
  12. }
  13. ?>

a kontruktor teraz wygląda tak
  1. <?php
  2. public function __construct(){
  3.  
  4. global $RBX_DB;
  5.  
  6. $this->getDB();
  7. # raportuj wszysrkie błedy z php
  8. }
  9. ?>

Pozostałość bez zmian.
Mam inne klasy, które dziedziczą po BaseClass i które wywołują w swoim kontruktorze kontruktor rodzica oraz korzystają z $this->doSQL(); Niestety wywołuje too błąd:
Kod
atal error: Cannot access empty property in C:\wamp\www\robotECS\core\classes\baseclass.php on line 141
(to ta linia 143 z pierwszego listingu)

Dlaczego właściwość jest pusta? Pewnie coś robię źle, jeśli tak to co? Czy wywołanie $this->db->jakaśFunkcja() w funkcjach dziedziczacych po baseClass jest porpawne jeśli nie to jak to robić?
orson
witam ...

Zamień $this->db na self:$db - to jest static ... ale też nie wiem czy będzie działać (musisz chyba przepisać to do zmiennej bo nie pamiętam czy można napisać self:biggrin.gifb->metoda)

pozdrawiam
Aztech
Zmieniłem wszędzie w klasie bazowej na self::$db i póki co wszystko działa.
Z innej beczki.
Mam klasę User dziedziczącą po BaseClass i funkcję która wywołuje mi coś takiego:
  1. <?php
  2. function getUserInfoById($user_id) {
  3. $user = new User($user_id);
  4. $user->readDataFromSqlById();
  5. $pdo = $user->getDB();
  6. #ilość postów napisanych przez użytkownika
  7. $stmt=$pdo->prepare('SELECT count(*) as posts FROM rbx_posts WHERE author_id='.$user_id);
  8. $stmt->execute();
  9. /* i dalej leci jakiś tam kod ...*/
  10. }
  11. ?>

konstruktor usera wywołuje kostruktor bazowy: parent::__construct()
Jeśli dobrze rozumiem to:
- dzięki temu co napisałem (mam nadieję, że to dobry Singleton jest biggrin.gif) jeśli była stworzona już instancja $db to nie powstanie mi nowa, tylko będę korzystał z już istniejącej
- $pdo = $user->getDB(); zwróci mi do zmiennej $pdo tego static $db dzięki czemu nie postanie żadne nowe połączenie tylko będę korzystał z już istniejącego

Pytanie za 100pkt. Jak sprawdzić czy działa to tak jak napisałem tzn czy mimo wszystko jakimś cudem nie jest tworzone nowe połączenie do bazy?
orson
witam

$user = new User($user_id); daje nowy obiekt ... musisz odwoływać się przez getDB ($user = BaseClass::getDB)

by sprawdzić ile razy tworzy się pdo wewnątrz getDB w ifie daj sobie printa albo jakieś logowanie do pliku

a tak wogóle to powinno być tak: konstruktor powinien być private i do obiektu powieneś się odwoływać tylko przez ::getDB z klas potomnych oraz z zewnątrz ... tworzenie pdo przenieś do konstrukra ... i w getDB tylko zwracanie zapisanej instancji ...

pozdrawiam
Aztech
Pobawiłem się trochę moim kodem i okazało się, że chyba nie jest to do końca Singleton albo ja coś spaprałem.
Oto co zrobiłem
BaseClass.php
  1. <?php
  2. /**
  3.    * Połaczenie z bazą danych
  4.    *
  5.    * @var array Przechowuje identyfiaktor połączenia z bazą danych.
  6.    * @access private
  7.    */
  8. private static $db = false;
  9.  
  10. /* ... */
  11.  
  12. /**
  13.    * Konstruktor
  14.    *
  15.    * @access public
  16.    */
  17. public function __construct(){
  18.  
  19. global $RBX_DB;
  20.  
  21. if (self::$db == false) {
  22. self::$db = new PDO('mysql:host='.$RBX_DB['host'].';dbname='.$RBX_DB['name'], $RBX_DB['user'], $RBX_DB['pass']);
  23. # raportuj wszystkie błędy z PDO
  24. self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  25. #polskie litery
  26. #wykonaj zapytanie i zapisz do wyników
  27. $stmt = self::$db->prepare('SET NAMES latin2; SET collation_connection = latin2_general_ci;');
  28. $stmt->execute();
  29. echo '<br>Tworzę połączenie z bazą danych';
  30. }
  31.  
  32. # raportuj wszysrkie błedy z php
  33. }
  34.  
  35. /* ... */
  36.  
  37. /**
  38.    * Zwróc obiekt połączenia z bazą
  39.    *
  40.    * @return array Tablica z identyfiaktorem połączenia z bazą danych
  41.    * @access public
  42.    */  
  43. public static function getDB(){
  44. return self::$db;
  45. }
  46.  
  47. /* ... */
  48.  
  49. /**
  50. * Wywołanie wszytkich metod związanych z wykonaniem zapytanie w jednej funkcji
  51.    * treść zapytania zostaje zapamiętana
  52.    *
  53.    * @param string $sql Zapytanie SQL
  54.    * @access public
  55.    * @return boolean
  56.    */
  57. public function doSQL($sql=''){
  58.  
  59. # gdy niepusty to zapisz zapytanie SQL
  60. if (!empty($sql)) $this->setSql($sql);
  61.  
  62. #wykonaj zapytanie i zapisz do wyników
  63. $stmt = self::$db->prepare($this->getSql());
  64. $stmt->execute();
  65. $this->result = $stmt->fetchAll(PDO::FETCH_ASSOC);
  66. if (isset($this->result[0])) {
  67.  $this->result = $this->result[0];
  68.  } 
  69. $stmt->closeCursor();
  70. return $this->checkResult();
  71. }
  72. ?>

Później podczas logowania wywoływana jest klasa LoginUSer, która dziedziczy po User a ta po BaseClass, loguję się do aplikacji, czyli jest tworzona instancja obiektu user, wywołuje się kontruktor BaseClass.php, można się zatem odwołać do połączenia z bazą poprzez BaseClass:$db i tutaj się myliłem, bo taki kod nie chce mi zadziałąć.
  1. <?php
  2. /**
  3.  * Zwraca listę forów wyświetlanych wg ustalonej kolejności (wg app_order a nie wg id)
  4.  *
  5.  * @return array tablica asocjacyjna
  6.  */
  7. function getForumList()
  8. {
  9. $pdo = BaseClass::getDB();
  10. $stmt=$pdo->prepare("SELECT * FROM rbx_forums AS rf"
  11. ." LEFT JOIN rbx_permissions AS rp ON rf.forum_id=rp.forum_id"
  12. ." WHERE rp.subforum_id=0 AND rp.topic_id=0"
  13. ." ORDER BY rf.app_order ASC"); 
  14. $stmt->execute();
  15. return $stmt->fetchAll(PDO::FETCH_ASSOC);
  16. }
  17. ?>


Czy ma jakiekolwiek znaczenie to, że instancja klasy user jest wywoływana w pliku index.php a getForumList() w rbx.php?
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.