Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Klasa w klasie?
Forum PHP.pl > Forum > PHP > Object-oriented programming
Tarcil
Witam serdecznie!

Od jakiegoś czasu próbuję opanować OOP w PHP i idzie mi, nie przymierzając, słabo. Mój problem polega na tym, że nie potrafię z jednej klasy odwołać się do metod innej. Nie wiem, czy to nie jest przypadkiem durnota jakaś i mój błąd w próbie myślenia obiektowo... proszę o pomoc w każdym bądź razie.

Mam klasę MySqlEng(). Konstruktor tej klasy tworzy połączenie z bazą danych i zapisuje uchwyt połączenia w prywatnej zmiennej klasy. Dalej mam 4 metody: selectQuery, updateQuery, insertQuery i deleteQuery, które przygotowują w prywatnej zmiennej $query string, który metodzie doQuery() służy do wykonania odpowiedniego zapytania w bazie danych. Dochodzi jeszcze metoda fetchResults(), która pozwala na przewijanie rekordów uzyskanych w odpowiedzi na zapytanie.

Standardowo używam tej klasy tak:
  1. <?php
  2. $sql = new MySqlEng();
  3.  
  4. $sql -> selectQuery('nazwa, ilosc', 'produkty', 'id > 93');
  5. while($res = $sql->fetchResults())
  6. {
  7. echo $res['nazwa'].' pozostała ilość: '.$res['ilosc'].'<br />';
  8. }
  9. ?>


Próbuję teraz złożyć klasę pagesSupport(), której zadaniem będzie: dodawanie stron do bazy danych, ich edycja i zmiana, oraz wyciągnie z bazy danych o odpowiedniej podstronie i wyswietlanie jej na ekranie. Zwykłe użycie wewnątrz metody tej klasy metody $sql->selectQuery() wywołuje błąd...

Jak skorzystać z klasy MySqlEng() wewnątrz klasy pagesSupport()questionmark.gif

Podaję też kod klasy MySqlEng():
  1. <?php
  2. //config
  3.    //this data should be inserted in another file, which is not available  by http://
  4.    define('DATABASE_HOST', 'localhost');
  5.    define('DATABASE_USER', 'tarcil_gsms');
  6.    define('DATABASE_PASS', 'gsms123');
  7.    define('DATABASE_NAME', 'tarcil_gsms');
  8.    
  9.    class MySqlEng
  10.        {
  11.        private $handler;
  12.        public $query;
  13.        private $results;
  14.        private $affected_rows;
  15.        private $last_row_id;
  16.        private $selected_rows;
  17.        public $records = array();
  18.        
  19.        
  20.        public function __construct()
  21.            {
  22.            if(@!$sql_handler = mysql_connect(DATABASE_HOST, DATABASE_USER, DATABASE_PASS))
  23.                {
  24.                throw new Exception('Problem z połączeniem do bazy danych.<br />Nr błędu: <b>'.mysql_errno().'</b><br /><b>Komunikat: </b>'.mysql_error());
  25.                }
  26.            else
  27.                {
  28.                if(!mysql_select_db(DATABASE_NAME))
  29.                    throw new Exception('Problem z wybraniem bazy danych.<br />Nr błędu: <b>'.mysql_errno().'</b><br /><b>Komunikat: </b>'.mysql_error());
  30.                else
  31.                    {
  32.                    //connection successfull:
  33.                    $this->handler = $sql_handler;
  34.                    unset($sql_handler);
  35.                    }
  36.                }
  37.            }
  38.            
  39.        //next four methods create sql query for doQuery method;
  40.        public function selectQuery($fields, $table, $where = "", $order = "", $limit = "")
  41.            {            
  42.            //if is another query saved:
  43.            if($this->query) unset($this->query);
  44.            
  45.            //creating query for doQuery() method
  46.            $this->query = 'SELECT '.$fields.' FROM '.$table;
  47.            if($where)
  48.                $this->query .= ' WHERE '.$where;
  49.            if($order)
  50.                $this->query .= ' ORDER BY '.$order;
  51.            if($limit)
  52.                $this->query .= ' LIMIT '.$limit;
  53.                
  54.            $this->doQuery();
  55.            $this->selected_rows = mysql_num_rows($this->results);
  56.            }
  57.            
  58.        TUTAJ SĄ JESZCZE TRZY METODY DO USTAWIANIA ZMIENNEJ QUERY... (updateQuery, deleteQuery, insertQuery)
  59.  
  60.            
  61.        //here is private method which will really make operations in db. it gets no arguments - all are written in object properties.
  62.        
  63.        private function doQuery()
  64.            {
  65.            if(!$this->results = mysql_query($this->query, $this->handler))
  66.                {
  67.                throw new Exception('Problem z wywołaniem zapytania do bazy danych.<br />Nr błędu: <b>'.mysql_errno().'</b><br /><b>Komunikat: </b>'.mysql_error());
  68.                }
  69.            }
  70.        
  71.        public function fetchResults()
  72.            {
  73.            if($this->results)
  74.                {
  75.                $this->records = mysql_fetch_array($this->results, MYSQL_ASSOC);
  76.                
  77.                if(is_array($this->records))
  78.                    {
  79.                    return $this->records;
  80.                    }
  81.                }
  82.            }
  83.            
  84.        public function getAffectedRows()
  85.            {
  86.            return $this->affected_rows;
  87.            }
  88.        public function getSelectedRows()
  89.            {
  90.            return $this->selected_rows;
  91.            }
  92.        public function getLastRowId()
  93.            {
  94.            return $this->last_row_id;
  95.            }
  96.        
  97.        public function __destruct()
  98.            {
  99.            mysql_close($this->handler);
  100.            }
  101.        }
  102. ?>
Crozin
Albo przekazujesz obiekt klasy MysqlEng do obiektu klasy pagesSupport poprzez argument jakiejś metody/konstruktora:
  1. <?php
  2.  
  3. require_once 'mysqleng.class.php';
  4. require_once 'pagessupport.class.php';
  5.  
  6. $db = new MysqlEng();
  7. $ps = new pagesSupport('jakies', 'arg.', $db);
  8. ?>
A w konstruktorze bądź innej metodzie:
  1. <?php
  2. public function __construct($abc, $def, MysqlEng $db){
  3.  //...
  4.  $this->db = $db; //$this->db to jakies pole prywatne
  5. }
  6. ?>


Albo korzystając z Singletonu, Rejestru czy jeszcze czegos innego, byle nie globali.


EDIT:
I to o co pytasz to obiekt wewnątrz obiektu. PHP nie umożliwia zapiania klasy w klasie (nested classes).
plurr
takie rzeczy to tylko w javie smile.gif A szkoda.
LBO
To o czym pisze kolega Crozin to tak zwane inversion of control.
TDzieki temu możesz uczynić kod bardziej uniwersalnym.

  1. <?php
  2. /*
  3.  * Ogólny interfejs dla abstrakcji zapytań.
  4.  *
  5.  * Interfejs wymusza na klasie go implementującej posiadanie odpowiednich metod.
  6.  *
  7.  */
  8. interface DatabaseQueries
  9. {
  10.    public function __construct(array $config);
  11.  
  12.    public function selectQuery();
  13.  
  14.    public function updateQuery();
  15.  
  16.    public function deleteQuery();
  17.  
  18.    public function  insertQuery();
  19. }
  20.  
  21. // omijam z lenistwa argumenty dla metod :)
  22. class MySqlQueries implements DatabaseQueries
  23. {
  24.    public function __construct(array $config)
  25.    {
  26.        // implementujesz łączenie się z bazą na podstawie tablicy $config dla MySQL
  27.    }
  28.  
  29.    public function selectQuery()
  30.    {
  31.        // implementujesz zapytanie dla MySQL
  32.    }
  33.  
  34.    public function updateQuery()
  35.    {
  36.        // implementujesz zapytanie dla MySQL
  37.    }
  38.  
  39.    public function deleteQuery()
  40.    {
  41.        // implementujesz zapytanie dla MySQL
  42.    }
  43.  
  44.    public function  insertQuery()
  45.    {
  46.        // implementujesz zapytanie dla MySQL
  47.    }
  48. }
  49.  
  50. // omijam z lenistwa argumenty dla metod :)
  51. class SQLiteQueries implements DatabaseQueries
  52. {
  53.    public function __construct(array $config)
  54.    {
  55.        // implementujesz łączenie się z bazą na podstawie tablicy $config dla SQLite
  56.    }
  57.  
  58.    public function selectQuery()
  59.    {
  60.        // implementujesz zapytanie dla SQLite
  61.    }
  62.  
  63.    public function updateQuery()
  64.    {
  65.        // implementujesz zapytanie dla SQLite
  66.    }
  67.  
  68.    public function deleteQuery()
  69.    {
  70.        // implementujesz zapytanie dla SQLite
  71.    }
  72.  
  73.    public function  insertQuery()
  74.    {
  75.        // implementujesz zapytanie dla SQLite
  76.    }
  77. }
  78. ?>


a potem:

  1. <?php
  2. $config = array(
  3. 'host' => 'localhost',
  4. 'user' => 'username',
  5. // etc
  6. );
  7.  
  8. $db = new MysqlQueries($config);
  9. $ps = new pagesSupport();
  10. $ps->setDatabase($db);
  11. ?>


lub

  1. <?php
  2. $config = array(
  3. 'filename' => '/usr/data/database.sqlite3'
  4. );
  5.  
  6. $db = new SQLiteQueries($config);
  7. $ps = new pagesSupport();
  8. $ps->setDatabase($db);
  9. ?>


I dzięki temu możesz w pewnym ograniczonym stopniu zmieniać bazę bez ingerencji w kod.

Jak widzisz użyłem metody (tzw setter), żeby przekazać klasę odpowiedzialną za zapytania na bazie danych. Jest to wygodniejsze od parametru w konstruktorze.

Cytat(Crozin @ 28.12.2008, 13:06:41 ) *
Albo korzystając z Singletonu, Rejestru czy jeszcze czegos innego, byle nie globali.


A powiedz czym się różni w użytkowaniu taki Rejestr od globali, prócz ujęcia w OOP?
wlamywacz
Cytat
A powiedz czym się różni w użytkowaniu taki Rejestr od globali, prócz ujęcia w OOP?

Różni się tym że nie możesz go nadpisać, raz ustalony i tak zostaje do końca.
LBO
Cytat(wlamywacz @ 1.01.2009, 20:23:56 ) *
Różni się tym że nie możesz go nadpisać, raz ustalony i tak zostaje do końca.


Nie rozumiem. Chodzi Tobie o to, że nie można nadpisać obiektów, które trzyma? Bo jak tak to muszę Ciebie zmartwić - powszechne implementacje nie biorą Tego pod uwagę (patrz Zend_Registry) i szczerze mówiąc takie podejście nie wynika jakoś jasno z założen tego wzorca.
wlamywacz
Każdy dostosowuje wzorzec do swoich potrzeb, nie są one sztywno ustalone.
LBO
Cytat(wlamywacz @ 1.01.2009, 23:24:24 ) *
Każdy dostosowuje wzorzec do swoich potrzeb, nie są one sztywno ustalone.


1. Tym bardziej nie możesz tego używać jako argumentu.
2. Taki sposób nie jest zbyt wygodny wbrew pozorom. Zakładam, że nie robisz testów jednostkowych.
3.
Cytat
[...] szczerze mówiąc takie podejście nie wynika jakoś jasno z założen tego wzorca.
pinochet
Cytat(Tarcil @ 28.12.2008, 12:42:42 ) *
... nie potrafię z jednej klasy odwołać się do metod innej.

No niestety tak się czasem zdarza, że w schemacie klas są pomiędzy nimi strzałki :] I wtedy tak jak koledzy pokazali przekazujemy referencję do obiektu w konstruktorze lub innej meodzie importującej ( nie jest to oczywiście jedyne rozwiązanie ale jest najlepsze)

Co do rejestru ... chciałem tylko powiedzieć, że w zasadzie nie różni się od globali ale czy BD różni się od globali ? Nie - no właśnie dlatego tworzymy warstwę danych aby wszystko co z nimi związane było "gdzieś" a nie wszędzie :]

@plurr oprócz Javy na świecie jest jeszcze jeden język: C# tongue.gif BTW PHP nie jest OO :[
wrzasq
@pinochet: jest wiele języków, a nested classes to nawet w C++ istnieją winksmiley.jpg. taki offtopic mały jak już chcemy uściślać tongue.gif.
phpion
Cytat(pinochet @ 3.01.2009, 06:56:25 ) *
BTW PHP nie jest OO :[

OO? Object Oriented? Jeśli tak to cię zmartwię: PHP, podobnie jak np. C++, jest językiem zorientowanym obiektowo, natomiast nie jest (jak np. Java) językiem obiektowym.
LBO
Cytat(phpion @ 3.01.2009, 18:24:02 ) *
językiem zorientowanym obiektowo / językiem obiektowym.



To ja też Ciebie zmartwię - nie ma czegoś takiego jak język zorientowany obiektowo smile.gif
phpion
Cytat(LBO @ 3.01.2009, 20:32:01 ) *
To ja też Ciebie zmartwię - nie ma czegoś takiego jak język zorientowany obiektowo smile.gif

worriedsmiley.gif jak to w takim razie jest? Mnie na uczelni uczono właśnie takiego rozgraniczenia.

// Edit:
Język zorientowany obiektowo - umożliwia pisanie kodu zarówno stukturalnie jak i obiektowo.
Język obiektowy - umożliwia pisanie kodu tylko obiektowo.
Tak mnie uczono...
LBO
OO to jest paradygmat... natomiast języki mogą mieć typy np. obiektowy język albo język z elementami tegoż tongue.gif

edit:

Chcę tylko udowodnić, że nie warto się czepiać takich rzeczy - bo to normalne, że w naszym środowisku z czasem zaczynamy operować skrótami myślowymi.

Co złego to nie ja smile.gif

Alan
Tarcil
Wielki dzięki smile.gif Przepraszam, że tu nie zaglądałem, ciężki okres ostatnio w pracy miałem. Serdecznie pozdrawiam smile.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.