[PHP] Classes en onderlinge method calls

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
Graag zou ik willen weten hoe ik mijn probleem het beste kan aanpakken.

De bedoeling is om vanuit een method in de class Page een query uit te voeren. Dit "moet" volgens mij wel met database::query(). Ik snap niet helemaal goed waarom $database->query() niet werkt. Vanuit de scope van de method in het object $page is het object $database niet zo te bereiken. Maar als ik het op de :: manier doe, dan werkt $this in de class Database niet, die ik nodig heb om $queryContainer te updaten. Volgens mij is het ook niet de bedoeling om bijv. Database te extenden aan Page.

De idee hierachter is overigens dat ik gewoon alle queries wil verzamelen in deze property en die aan het eind van de pagina wil tonen (met $database->queryContainer). Misschien dat ik dat uiteindelijk beter kan doen met een aparte klasse Debug, maar ook dan zal zich wel een soortgelijk probleem voordoen. Dit is ook wel bedoeld om mijn begrip over classes etc. te verbeteren.

Dit is een beetje de flow van mijn pagina (waar het om gaat):
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
include_once PATH_CLASSES.'page.class.php';
include_once PATH_CLASSES.'database.class.php';

$page = new Page($page_id);
$database = new Database();

include_once 'inc/template.inc.php';

// een method uit page.class.php:

class Page {

    function Page($id) {
        $this->id = $id;
    }

    function getDetails() {
        
        /*
        ** function getPageDetails()
        ** retreive current page data from db
        */
        
        $query = 'SELECT ...';
        $result = database::query($query);
        $aPageDetails = mysql_fetch_assoc($result);
    }
}

// en een stuk uit database.class.php:

class Database {
    
    var $queryContainer;
    
    function Database() {
        $this->queryContainer = array();
    }
    
    function query($query) {
        
        if(DEBUG) $this->queryContainer[] = $query;
 
        $result = mysql_query($query);
        
        if (!$result) {
            $message  = 'Invalid query: ' . mysql_error() . "<br>\n";
            $message .= 'Whole query: ' . $query;
            die($message);
        } else {   
            return $result;    
        }
    }
}

[ Voor 4% gewijzigd door X-Lars op 31-10-2005 18:20 ]


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Waarom instantieer je je Database class dan niet binnen de constructor van je Page class?
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Page {

    function Page($id) {
        $this->id = $id;
        $this->database = new Database();
    }

    function getDetails() {
        
        /*
        ** function getPageDetails()
        ** retreive current page data from db
        */
        
        $query = 'SELECT ...';
        $result = $this->database-->query($query);
        $aPageDetails = mysql_fetch_assoc($result);
    }
}


Alternatief is een overkoepelende class (bijvoorbeeld een Engine class) waarbinnen je al je classes instantieert (en property maakt van je Engine class) waarbij je aan elke class instantie een referentie naar je Engine class meegeeft.

[ Voor 19% gewijzigd door crisp op 31-10-2005 18:28 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • _Gekkie_
  • Registratie: Oktober 2000
  • Laatst online: 24-06 20:21

_Gekkie_

And the cow said: Helloooooow?

of je globalt je db-handle in je methode (of refereert naar je global handle in je constructor zoals crisp aangeeft)

Het voordeel van 1 db-object zou al kunnen zijn dat je gebruik kunt maken van je p-connects!

Gekkie is a proud member of TheBenny!


Acties:
  • 0 Henk 'm!

  • eghie
  • Registratie: Februari 2002
  • Niet online

eghie

Spoken words!

dat met :: is als je een class niet hebt geinstantieerd. Dat heb je in dit geval wel gedaan, maar vervolgens roep je de classe direct aan en niet de instantie. Nu moet je de instantie dus aanroepen met:
PHP:
1
$database->query()

Nu klopt het dat dit niet werkt, aangezien je er niet bij kunt. $database is een globale variable. Die zou je moeten kunnen benaderen door global $database; te gebruiken.

Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
OK, tnx folks!

De oplossing van Crisp werkt op zich perfect. Alleen nu vind ik het gewoon niet zo logisch om $database in $page te instantieren, uit OO-oogpunt zeg maar. Ik zie ze meer als aparte classes. Maar ik kan er wel mee leven hoor, nu is Page mijn 'Engine' class a.h.w. Ik zal nog eens kijken hoe ik dat uit ga werken.

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Het kan ook anders:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$database = new Database();
$page = new Page($page_id, $database);

class Page {

    function Page($id, &$database) {
        $this->id = $id;
        $this->database =& $database;
    }

    function getDetails() {
        
        /*
        ** function getPageDetails()
        ** retreive current page data from db
        */
        
        $query = 'SELECT ...';
        $result = $this->database-->query($query);
        $aPageDetails = mysql_fetch_assoc($result);
    }
}


Maar dan vind ik het persoonlijk netter om alles in 1 superclass te doen ipv de global namespace te vervuilen ;)

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • JHS
  • Registratie: Augustus 2003
  • Laatst online: 16-09 16:02

JHS

Splitting the thaum.

Wat crisp als tweede suggestie doet, feitelijk een singleton class, is in mijn ogen voor een database handler veel logischer, aangezien je er daar (bijna) altijd maar één van wilt. Zie hier (beste voorbeeld / code in mijn ogen, let ook op de andere pagina's in dit artikel), of hier, of hier voor een complete "registry class". Let bij deze voorbeelden wel op eventuele references / php4 <> php5 problemen :) .

[ Voor 18% gewijzigd door JHS op 31-10-2005 19:57 ]

DM!


Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

JHS schreef op maandag 31 oktober 2005 @ 19:17:
Wat crisp als tweede suggestie doet, feitelijk een singleton class, is in mijn ogen voor een database handler veel logischer, aangezien je er daar (bijna) altijd maar één van wilt.
Zoals crisp het uitvoert (het expliciet meegeven van een db object aan Page), is het _geen_ singleton.

Als het een singleton was; hoefde je juist niet het db object mee te geven. Dan kon page gewoon zo zijn

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Page
{
    var $db
      
    function page(){
        $this->db = DB::getInstance();
    }
}

class DB
{
    static $instance
     
    function DB(){
        // Connect enzo   
    }
    
    function getInstance()
    {
        // Als er nog geen instantie is; maak er één
        if($this->instance == null)
            $this->instance = new DB()
        
        return $this->instance;
    }
}


Ik weet niet zeker hoe het ook alweer ging met static vars en php, maar daar kom je vast wel uit :P

[ Voor 25% gewijzigd door eamelink op 31-10-2005 19:48 ]


Acties:
  • 0 Henk 'm!

  • JHS
  • Registratie: Augustus 2003
  • Laatst online: 16-09 16:02

JHS

Splitting the thaum.

eamelink schreef op maandag 31 oktober 2005 @ 19:46:
[...]


Zoals crisp het uitvoert (het expliciet meegeven van een db object aan Page), is het _geen_ singleton.
Mja, ik moet beter lezen. Alhoewel hij "Alternatief is een overkoepelende class (bijvoorbeeld een Engine class) waarbinnen je al je classes instantieert (en property maakt van je Engine class) waarbij je aan elke class instantie een referentie naar je Engine class meegeeft." suggereerde, wat ook niet is wat jij zij ;) . Doet echter niks af aan wat ik verder zei :P .
Ik weet niet zeker hoe het ook alweer ging met static vars en php, maar daar kom je vast wel uit :P
Iniedergeval werkt "var $foo" niet, iirc, maar dat is niet relevant in deze inderdaad :) .

[ Voor 3% gewijzigd door JHS op 31-10-2005 19:57 ]

DM!


Acties:
  • 0 Henk 'm!

  • Sybr_E-N
  • Registratie: December 2001
  • Laatst online: 21-09 12:54
offtopic:
In PHP4 zul je nog wat creatief met references moeten strooien, maar voor PHP5 staan dit soort dingen ook al in de manual.

Acties:
  • 0 Henk 'm!

Verwijderd

X-Lars schreef op maandag 31 oktober 2005 @ 18:32:
De oplossing van Crisp werkt op zich perfect. Alleen nu vind ik het gewoon niet zo logisch om $database in $page te instantieren, uit OO-oogpunt zeg maar. Ik zie ze meer als aparte classes. Maar ik kan er wel mee leven hoor, nu is Page mijn 'Engine' class a.h.w. Ik zal nog eens kijken hoe ik dat uit ga werken.
Til niet te zwaar aan OO oogpunt, want ik durf te wedden dat je nu user/pass/etc.. in je "DataBase" klasse hebt...

Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

Verwijderd schreef op maandag 31 oktober 2005 @ 20:05:
[...]
Til niet te zwaar aan OO oogpunt, want ik durf te wedden dat je nu user/pass/etc.. in je "DataBase" klasse hebt...
Ik denk dat de meeste mensen die wel gewoon in een config file hebben hoor :P

Acties:
  • 0 Henk 'm!

Verwijderd

eamelink schreef op maandag 31 oktober 2005 @ 20:11:Ik denk dat de meeste mensen die wel gewoon in een config file hebben hoor :P
Ik had het over de properties zelf, niet de values.

Ik denk dat de meeste OO programmeurs helemaal geen "database" klasse hebben ;)

Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
eamelink schreef op maandag 31 oktober 2005 @ 19:46:
Ik weet niet zeker hoe het ook alweer ging met static vars en php, maar daar kom je vast wel uit :P
In PHP4 heb je die enkel op functie (en method..) niveau, in PHP5 ook op class niveau.
X-Lars schreef op maandag 31 oktober 2005 @ 18:32:
Alleen nu vind ik het gewoon niet zo logisch om $database in $page te instantieren, uit OO-oogpunt zeg maar.
Inderdaad, die Page heeft vrij weinig met een Database te maken, je brengt immers nogsteeds geen scheiding aan tussen verschillende lagen in je applicatie.
Verwijderd schreef op maandag 31 oktober 2005 @ 20:20:
Ik denk dat de meeste OO programmeurs helemaal geen "database" klasse hebben ;)
Als leermoment Waarom niet? Zelf vind ik het prettig om vanuit mijn DAO's tegen een abstractere Database class aan te praten, in plaats van direct met specifieke database (wat dan vaak op MySql neer komt).

Acties:
  • 0 Henk 'm!

Verwijderd

PrisonerOfPain schreef op maandag 31 oktober 2005 @ 20:31:
Als leermoment Waarom niet? Zelf vind ik het prettig om vanuit mijn DAO's tegen een abstractere Database class aan te praten, in plaats van direct met specifieke database (wat dan vaak op MySql neer komt).
Puur naamgeving. Een Database is een verzameling van (gerelateerde) tabellen. Een gebruiker heeft toegang tot een database maar is zelf geen onderdeel van de database. Dus gebruikersnaam/wachtwoord etc behoren niet toe aan een klasse die database heet. Ik praat dus liever over bijvoobeeld een datasource en een connection.

Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
De Singleton-class is een mooie oplossing. Ik ga maar even heel hard mijn boeken uit de kast slepen, want daar staat vast het een en ander in als het goed is. Mocht daar nog wat uit voortvloeien, dan zal ik het met jullie delen. Echter zat ik op het werk ten tijde van het probleem. En het moet inderdaad in PHP4, dat was ik vergeten te melden.

De naamgeving 'Database' is misschien wat ongelukkig gekozen voor een class. Bijvoorbeeld $connection->connect en $datasource->executeQuery klinkt allemaal logischer.

Overigens heb ik db/user/pass/etc. in een config-file staan, maar dat is dan ook voor de back-end (CMS), dus dat laat ik daar lekker staan.

Acties:
  • 0 Henk 'm!

Verwijderd

X-Lars schreef op maandag 31 oktober 2005 @ 21:07:
De naamgeving 'Database' is misschien wat ongelukkig gekozen voor een class. Bijvoorbeeld $connection->connect en $datasource->executeQuery klinkt allemaal logischer.
datasource:
driver informatie
database naam
etc

connection
user pass etc

statement
sql etc

een connectie kun je maken met een datasource (of op de datasource, das puur perspectief). Een statement voor je uit over een connectie.

Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
crisp schreef op maandag 31 oktober 2005 @ 18:25:
[...]
Alternatief is een overkoepelende class (bijvoorbeeld een Engine class) waarbinnen je al je classes instantieert (en property maakt van je Engine class) waarbij je aan elke class instantie een referentie naar je Engine class meegeeft.
Hoe werkt dit precies?

Ik heb nu dit:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Engine {
    
    var $page;
    var $database;
    var $debug;

    function Engine() {
        $this->page = Page::getInstance($_GET['page_id']);
        $this->database = Database::getInstance();
        $this->debug = Debug::getInstance();
        // Volgens mij zijn dit allemaal classes die maar 1 keer nodig zijn (> singleton)
    }
}

// En bijv.:

class Page {

    function Page($id) {
        $this->id = $id;
    }

    function getInstance ($id) {
        
        static $instance;
        
        if($instance == null) {
            $instance = new Page($id);
        }
        return $instance;
        
    }
    [...]
}

Hoe kan ik nu vanuit een method in object Page een method in object Database aanroepen?

Edit: ja, met bijv. database::query, maar daar wilde ik nou juist vanaf.

[ Voor 5% gewijzigd door X-Lars op 01-11-2005 10:38 ]


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Je moet dan nog steeds een reference naar je engine object meegeven (ook wel handig om classes die nodig zijn in andere classes eerst te instantieren):
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Engine {
    
    var $database;
    var $page;

    function Engine() {
        $this->database = Database::getInstance();
        $this->page = Page::getInstance($_GET['page_id'], $this);
    }
}

class Page {

    function Page($id, &$engine) {
        $this->id = $id;
        $this->engine =& $engine;
    }

    function getInstance ($id) {
        
        static $instance;
        
        if($instance == null) {
            $instance = new Page($id);
        }

        return $instance;
    }

    function getDetails() {
        
        /*
        ** function getPageDetails()
        ** retreive current page data from db
        */
        
        $query = 'SELECT ...';
        $result = $this->engine->database-->query($query);
        $aPageDetails = mysql_fetch_assoc($result);
    }
}

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • sariel
  • Registratie: Mei 2004
  • Laatst online: 22-05-2024
Als je een wrapper hebt voor je database.....waarom dan nog steeds mysql_fetch_assoc gebruiken? Maak daar dan ook een wrapper voor. Het is niet netjes om een goede wrapper te hebben, en dan alsnog te klooien met harde (my)sql calls.

PHP:
1
2
3
4
5
6
7
8
9
class database
{
[...]
      function fetchArray()
      {
             return mysql_fetch_assoc($this->result);
      }
[...]
}

Copy.com


Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
Crisp, bedankt voor je antwoord. Maar hij geeft wel een in mijn ogen vreemde foutmelding, namelijk een missing argument 2 in line 14 (in jouw code), terwijl die toch echt wel wordt meegegeven:
PHP:
1
2
3
4
5
6
class Engine {
    var $page;
    function Engine() {
        $this->page = Page::getInstance($_GET['page_id'], $this);
    }
}

Ik kom er ook niet echt uit met bijv. deze hulp. Ik zal wel iets heel simpels over het hoofd zien.

Edit:
Oops...
PHP:
1
2
3
4
5
6
7
    function getInstance () {
        static $instance;
        if($instance == null) {
            $instance = new Page($this->engine);
        }
        return $instance;
    }

In getInstance van object Page moet het argument natuurlijk ook meegegeven worden...

[ Voor 25% gewijzigd door X-Lars op 01-11-2005 12:28 ]


Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
Nu snap ik het toch nog steeds niet goed.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Engine {
    var $page;
    function Engine() {
        $this->page = Page::getInstance($this);
        $this->database = Database::getInstance($this);
    }
}
class Page {
    var $engine;
    function Page(&$engine) {
        $this->engine =& $engine;
    }

    function getInstance () {
        static $instance;
        if($instance == null) {
            $instance = new Page($this->engine);
        }
        return $instance;
    }

    function getDetails() {
        $query = '';
        $aPageDetails = $this->engine->database->fetchArray($query);

Er wordt nu toch eigenlijk een $this->page = new Page() geinstantieerd vanuit Engine? Toch werkt bijv. de aanroep $this->engine->database->method niet (Call to a member function on a non-object). Als ik het singleton-idee loslaat en van line 4 $this->page = new Page($this) maak, gaat dat op zich wel goed. Maar ik wil gewoon zoals hierboven vanuit object $page een method aanroepen uit $database, terwijl dit instanties van Singleton classes zijn. Dat moet toch kunnen?

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

PHP:
1
2
3
4
5
6
7
    function getInstance (&$engine) {
        static $instance;
        if($instance == null) {
            $instance = new Page($engine);
        }
        return $instance;
    }

lijkt me

hoewel dit ook zou moeten werken:
PHP:
1
2
3
4
5
6
7
    function getInstance () {
        static $instance;
        if($instance == null) {
            $instance = new Page($this);
        }
        return $instance;
    }

aangezien je de static method call vanuit de Engine class doet zal $this in de getInstance method verwijzen naar je Engine class zelf (maar dat is wel een beetje smerig :P )

[ Voor 49% gewijzigd door crisp op 01-11-2005 12:36 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
Crisp, thanks again. But the story continues >:)

Het komt erop neer dat als ik nu in de constructor van het object $database de method $this->connect aanroep, hieruit niet normaal een method uit een ander object kan worden aangeroepen.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Database {
    var $engine;
    var $link;
    function Database(&$engine) {
        $this->engine =& $engine;
        $this->link = $this->connect();
    }
    
    function getInstance (&$engine) {
        [...]
    }
    
    function connect() {
        $this->link = mysql_connect($this->host, $this->user, $this->password);
        if(!$this->link) {
            $this->engine->debug->storeSQL('MYSQL_CONNECT', mysql_error(), mysql_errno());
            return false;
        } else {
            [...]
        }
    }
    function query($query) {
        $resource = mysql_query($query);
        $this->engine->debug->storeSQL($query, mysql_error(), mysql_errno());
        return $resource;
    }
}

Vanuit deze query() gaat de aanroep naar storeSQL() wel gewoon goed, edit: maar vanuit connect() niet. Dus volgens mij ligt het eraan, dat connect() in de constructor wordt aangeroepen; en dat daardoor de objecten nog niet geinstantieerd zijn :?

[ Voor 11% gewijzigd door X-Lars op 01-11-2005 15:42 ]


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Waarom doe je op regel 16 toch weer een static call?
En volgens mij zou je vanuit je functie connect een reference naar je connectie moeten returnen aangezien je die in regel 6 toewijst (en die toewijzing moet je dus niet in regel 14 doen).

[ Voor 13% gewijzigd door crisp op 01-11-2005 15:39 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
O sorry, die static call op 16 was een typo. Ik zal eerst met je andere aanwijzing even verder.

Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
Het probleem zit hem nog in die line 16.

Edit: als ik $database->connect() vanuit bijv. $engine aanroep, gaat het wel goed. Het zit hem er dus in dat connect() niet vanuit de constructor aangeroepen kan worden (wat betreft line 4 dan). Ik vind dat toch wel vreemd. Iemand suggesties?

Overigens is dit nu de method connect(), hier is het line 4:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
function connect() {
    $link = mysql_connect($this->host, $this->user, $this->password);
    if(!$link) {
        $this->engine->debug->storeSQL('MYSQL_CONNECT', mysql_error(), mysql_errno());
        return false;
    } else {
        if(!mysql_select_db($this->name, $link)) {
            $this->engine->debug->storeSQL('MYSQL_SELECT_DB', mysql_error(), mysql_errno());
            return false;
        }
    }
    return $link;
}

[ Voor 23% gewijzigd door X-Lars op 01-11-2005 16:07 ]


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

instantieer je je debug class wel voor je database class? (in de constructor van je Engine class)?

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.

Topicstarter
Ja, dat zie ik dus nu precies |:(
Pagina: 1