[PHP]Object creeren = app dood

Pagina: 1
Acties:
  • 1.882 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • MindStorm
  • Registratie: Juli 2002
  • Laatst online: 16-01-2024
Sinds ben ik bezig met het afstoffen van mijn PHP-kennis en meteen maar in OO PHP5 te springen. Ik kom nu echter een aantal keer het zelfde probleem tegen:

Wanneer ik een object aan probeer te maken (maakt weinig uit of het een eigen object is of een PEAR object) stopt de hele applicatie zonder foutmeldingen of wat dan ook.

Het komt nu voor met deze code:

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
<?php
/* Project: spcms
 * Filename: database.php 
 * Created on May 28, 2007 8:13:17 PM
 * 
 * @author Bob
 */

require_once 'MDB2.php';
require_once 'MDB2/Driver/mysql.php';


class Database {
    private $_dsn;
    private $_options;
    private $_conn;
    static $INSTANCE;
    private function __construct(Config $conf) {
        echo("construct");
        $this->_dsn = $conf->dbtype .'://'.$conf->dbuser.':'.$conf->dbpass.'@'.$conf->dbhost.'/'.$conf->dbname; 
        $this->_options = null; 
        
        $this->_conn =& MDB2::connect($this->_dsn, $this->_options);
        
        echo("DSN: ".$this->_dsn);
        
        if(PEAR::isError($this->_conn)) {
            echo("Fatal error: database connection failed.<br />");
            die($conn->getMessage());           
        } 
    }
    
    public static function getInstance() {
        echo("hi!<br />");
        if(!isset(self::$INSTANCE)) {
            echo("notset<br />");
            $c = __CLASS__;
            self::$INSTANCE = &new $c;
            echo("done");
        } else {
            echo("was set!");
        }
        echo("RETURNED instance");
        return self::$INSTANCE;
    }
    
    public function testMe(){
        echo("YAY!");
    }
}
?>


De output in dit voorbeeld is:

code:
1
2
hi!
notset


Een vergelijkbare situatie doet zich voor wanneer ik PEAR::Log gebruik met sql (MDB2).

Mijn ontwikkelomgeving is eclipse (php plugin). Voor het draaien van de scripts gebruik ik apache 2.2.4 en php 5.1.6, mysql 5.0.27. Dit hele gebeuren draait op een linux machine (Fedora Core 6).

Het is niet duidelijk wat er niet goed gaat en/of waarom niet, zowel de error_log als de access_log geven niets raars aan, ik zie alleen de request staan.

Heeft iemand dit eerder gehad en opgelost? Zie ik misschien iets heel duidelijks over het hoofd?

Het probleem is dus eigenlijk dat ik geen nieuwe instanties van classes aan kan maken, met de bovenstaande code.

[ Voor 2% gewijzigd door MindStorm op 30-05-2007 16:51 . Reden: beetje verduidelijking, later volgt meer ]


Acties:
  • 0 Henk 'm!

  • megamuch
  • Registratie: Februari 2001
  • Laatst online: 08-12-2024

megamuch

Tring Tring!

wat doet var_dump(self::$INSTANCE); ? en var_dump($c);?

edit

Als ik 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
35
36
37
38
39
40
<?php
/* Project: spcms
 * Filename: database.php 
 * Created on May 28, 2007 8:13:17 PM
 * 
 * @author Bob
 */


class Database {
    private $_dsn;
    private $_options;
    private $_conn;
    static $INSTANCE;
     function __construct() {
        echo("construct<br />");
    }
    
    public static function getInstance() {
        echo("hi!<br />");
        if(!isset(self::$INSTANCE)) {
            echo("notset<br />");
            $c = __CLASS__;
            self::$INSTANCE = &new $c;
            echo("done<br />");
        } else {
            echo("was set!");
        }
        echo("RETURNED instance<br />");
        return self::$INSTANCE;
    }
    
    public function testMe(){
        echo("YAY!");
    }
}
$a = new Database();
$a->getInstance();
var_dump($a);
?>

doe krijg ik
code:
1
2
3
4
5
6
7
construct
hi!
notset
construct
done
RETURNED instance
object(Database)#1 (3) { ["_dsn:private"]=> NULL ["_options:private"]=> NULL ["_conn:private"]=> NULL }


Of begrijp ik nu niet wat je wil? :?

[ Voor 90% gewijzigd door megamuch op 30-05-2007 00:16 ]

Verstand van Voip? Ik heb een leuke baan voor je!


Acties:
  • 0 Henk 'm!

  • Ciqniz
  • Registratie: Oktober 2002
  • Laatst online: 07-09-2023

Ciqniz

On the move...

Ik weet niet zeker of ik het goed begrijp maar,

Volgens mij probeer je de constructor te laden terwijl je een static methode aanroept? Als je in een klasse een constructor en een static methode hebt gaat deze constructor nooit uitgevoerd worden als je alleen die static methode oproept. Die constructor gaat alleen werken wanneer er een object gemaakt gaat worden van die klasse. Dan zul je echt alles via static methodes moeten doen icm static (private) vars. Een optie is om meerdere methodes die te maken gaan hebben met je database daarin een vaste methode mee te laten lopen die kijkt of de static (private) var geset is of niet. Als je het echt op deze manier wilt doen dan.

Nogmaals, ik weet niet zeker of je dat bedoelt, maar zo kwam het op mij over toen ik je code zag.

edit:
Je zegt trouwens niet wanneer je wat doet. Zo gebeuren er hele andere dingen binnenin je object en/of klasse bij:
PHP:
1
2
$blaat = new Database();
$blaat->testMe();


Dan bij:
PHP:
1
$blaat = Database::getInstance();


Waar gaat het bij jou fout? :?

[ Voor 15% gewijzigd door Ciqniz op 30-05-2007 08:11 ]


Acties:
  • 0 Henk 'm!

  • ikke007
  • Registratie: Juni 2001
  • Laatst online: 18-09 14:10
Naast dat je niet helemaal duidelijk uitlegt wat je nu precies doet (zie vorige reply) is een altijd handige debug tool de error reporting aanzetten
PHP:
1
ERROR_REPORTING(E_ALL);


nb: E_ALL bevat alle meldingen op E_STRICT na

Lets remove all security labels and let the problem of stupidity solve itself


Acties:
  • 0 Henk 'm!

  • evolnick
  • Registratie: Januari 2006
  • Laatst online: 04-06-2024
dan zul je de fout wel zien ja :)
de database constructor heeft namelijk 1 argument nodig, maar bij het aanmaken geef je geen argumenten mee.

Acties:
  • 0 Henk 'm!

  • MindStorm
  • Registratie: Juli 2002
  • Laatst online: 16-01-2024
megamuch schreef op dinsdag 29 mei 2007 @ 23:59:
wat doet var_dump(self::$INSTANCE); ? en var_dump($c);?

edit


...
[/code]
doe krijg ik
code:
1
2
3
4
5
6
7
construct
hi!
notset
construct
done
RETURNED instance
object(Database)#1 (3) { ["_dsn:private"]=> NULL ["_options:private"]=> NULL ["_conn:private"]=> NULL }


Of begrijp ik nu niet wat je wil? :?
Dat eerste ga ik zodirect testen. De output die jij krijgt is de output die je hoort te krijgen, maar bij mij stopt ie dus gewoon na
code:
1
 self::$INSTANCE = new Database();
Ciqniz schreef op woensdag 30 mei 2007 @ 08:07:
Ik weet niet zeker of ik het goed begrijp maar,

Volgens mij probeer je de constructor te laden terwijl je een static methode aanroept? Als je in een klasse een constructor en een static methode hebt gaat deze constructor nooit uitgevoerd worden als je alleen die static methode oproept. Die constructor gaat alleen werken wanneer er een object gemaakt gaat worden van die klasse. Dan zul je echt alles via static methodes moeten doen icm static (private) vars. Een optie is om meerdere methodes die te maken gaan hebben met je database daarin een vaste methode mee te laten lopen die kijkt of de static (private) var geset is of niet. Als je het echt op deze manier wilt doen dan.

Waar gaat het bij jou fout? :?
Volgensmij begrijp je het heel goed, dit zou best wel eens de fout kunnen zijn... slecht opgelet van mij
ikke007 schreef op woensdag 30 mei 2007 @ 11:23:
Naast dat je niet helemaal duidelijk uitlegt wat je nu precies doet (zie vorige reply) is een altijd handige debug tool de error reporting aanzetten
PHP:
1
ERROR_REPORTING(E_ALL);


nb: E_ALL bevat alle meldingen op E_STRICT na
Error reporting staat volgensmij al aan. Ik zal de TS even aanpassen, dan wordt het misschien duidelijker wat ik bedoel

[ Voor 56% gewijzigd door MindStorm op 30-05-2007 16:50 . Reden: dubbelpost ]


Acties:
  • 0 Henk 'm!

  • MindStorm
  • Registratie: Juli 2002
  • Laatst online: 16-01-2024
--

[ Voor 100% gewijzigd door MindStorm op 30-05-2007 16:48 . Reden: dubbelpost ]


Acties:
  • 0 Henk 'm!

Verwijderd

Maar begrijp ik nu goed dat je het Singleton Pattern wilt implementeren? Dat is namelijk in php vrij onzinnig gezien het ontbreken van een applicatie scope.

Acties:
  • 0 Henk 'm!

  • zwippie
  • Registratie: Mei 2003
  • Niet online

zwippie

Electrons at work

Verwijderd schreef op woensdag 30 mei 2007 @ 16:55:
Maar begrijp ik nu goed dat je het Singleton Pattern wilt implementeren? Dat is namelijk in php vrij onzinnig gezien het ontbreken van een applicatie scope.
Je hebt toch wel een request (script) scope?

How much can you compute with the "ultimate laptop" with 1 kg of mass and 1 liter of volume? Answer: not more than 10^51 operations per second on not more than 10^32 bits.


Acties:
  • 0 Henk 'm!

Verwijderd

zwippie schreef op woensdag 30 mei 2007 @ 17:04:
Je hebt toch wel een request (script) scope?
Ja, maar dat is toch niet interessant. Je kunt gewoon de instantie doorgeven aan de classes/functies die hem nodig hebben.

Acties:
  • 0 Henk 'm!

  • zwippie
  • Registratie: Mei 2003
  • Niet online

zwippie

Electrons at work

Verwijderd schreef op woensdag 30 mei 2007 @ 17:08:
[...]
Ja, maar dat is toch niet interessant. Je kunt gewoon de instantie doorgeven aan de classes/functies die hem nodig hebben.
Tsja, uiteindelijk zou je dat in elke applicatie kunnen doen maar om geen singleton te hoeven gebruiken. ;)


Misschien heeft de TS hier iets aan, volgens mij is het een correcte implementatie van het singleton pattern in PHP5, don't shoot me if I'm wrong:
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
<?php
class Database {

    private static $instance;
    private $iets = "iets";
    
    public function Database()
    {
        self::$instance =& $this;
    }

    public static function &get_instance()
    {
        return self::$instance;
    }

    public function set_iets($value)
    {
        $this->iets = $value;
    }

    public function get_iets()
    {
        return $this->iets;
    }
}

$db = new Database();
$db->set_iets("iets anders");

// later
$db2 =& Database::get_instance();
echo $db2->get_iets();
?>

How much can you compute with the "ultimate laptop" with 1 kg of mass and 1 liter of volume? Answer: not more than 10^51 operations per second on not more than 10^32 bits.


Acties:
  • 0 Henk 'm!

  • RedRose
  • Registratie: Juni 2001
  • Niet online

RedRose

Icebear

Wat mark platvoet bedoelt met het hebben van alleen de request scope is dat het vanwege het hebben van alleen die scope het vrij onzinnig is om een Singleton te implementeren, aangezien die class toch voor iedere request geinstantieerd wordt . Binnen die scope is het daarom handiger om de instantie door te geven aan code die deze nodig heeft en de Singleton in dit voorbeeld lekker te laten zitten. ;)

Sundown Circus


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
@zwippie:

Dat is dus fout. Kijk maar eens naar het resultaat als je dit doet:
PHP:
1
2
3
4
5
$db = new Database();
$db->set_iets("abc");
new Database();
$db2 = Database::get_instance();
print $db2->get_iets();

Dan krijg je dus "iets" als output, en geen "abc", wat je zou moeten hebben.

Zo is hij juist:
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
class Database {

    private static $instance;
    private $iets = "iets";
    
    private function Database()
    {
        
    }

    public static function get_instance()
    {
        if ( is_null(self::$instance) ) self::$instance = new Database();
        return self::$instance;
    }

    public function set_iets($value)
    {
        $this->iets = $value;
    }

    public function get_iets()
    {
        return $this->iets;
    }
}

// $db = new Database(); Error!
$db = Database::get_instance();
$db->set_iets("abc");
// new Database(); Error!
$db2 = Database::get_instance();
print $db2->get_iets();


Overigens hoef je in PHP5 geen references meer expliciet te gebruiken. Daar moet je bij objecten gewoon van afblijven. =& en een & voor een method is dus overbodig.

[ Voor 8% gewijzigd door Michali op 30-05-2007 20:07 ]

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • zwippie
  • Registratie: Mei 2003
  • Niet online

zwippie

Electrons at work

Ok, weer wat geleerd. :)

How much can you compute with the "ultimate laptop" with 1 kg of mass and 1 liter of volume? Answer: not more than 10^51 operations per second on not more than 10^32 bits.


Acties:
  • 0 Henk 'm!

  • Observer
  • Registratie: April 2001
  • Laatst online: 16:24
RedRose schreef op woensdag 30 mei 2007 @ 18:18:
Wat mark platvoet bedoelt met het hebben van alleen de request scope is dat het vanwege het hebben van alleen die scope het vrij onzinnig is om een Singleton te implementeren, aangezien die class toch voor iedere request geinstantieerd wordt . Binnen die scope is het daarom handiger om de instantie door te geven aan code die deze nodig heeft en de Singleton in dit voorbeeld lekker te laten zitten. ;)
Ook binnen 'slechts' een request scope is het Singleton pattern handig.
Je gaat geen database connectie aan tig classes meegeven. Wat als je meer dan 1 type database-engine gebruikt, of een Master/Slave-setup? Ga je voor elke database die connectie meegeven?

Het is handiger om dit via een Singleton te regelen. Zo wordt elke database ook maar 1 keer aangeroepen en kan elke class/method zelf bepalen welke connectie die gebruikt.

There are 10 kinds of people in the world: those that understand binary and those that don't


Acties:
  • 0 Henk 'm!

  • MindStorm
  • Registratie: Juli 2002
  • Laatst online: 16-01-2024
Ik wil inderdaad het singleton pattern implementeren, omdat ik gemakkelijk steeds van dezelfde databaseconnectie wil maken binnen dezelfde request scope. Ik ga nu even de tips van eerder vandaag uitproberen, kijken of dat wat uithaalt.

edit: ik heb de fout gevonden, het was een soort van overblijfsel van eerdere code

code:
1
2
3
4
private function __construct(Config $conf);

werd nu
private function __construct();


error_reporting(E_ALL) deed het hem, de error reporting stond toch niet goed. Even kijken of de Log nu ook constructiever is met zijn error messages is

[ Voor 37% gewijzigd door MindStorm op 30-05-2007 20:40 ]


Acties:
  • 0 Henk 'm!

  • RedRose
  • Registratie: Juni 2001
  • Niet online

RedRose

Icebear

Observer schreef op woensdag 30 mei 2007 @ 20:31:
[...]


Ook binnen 'slechts' een request scope is het Singleton pattern handig.
Je gaat geen database connectie aan tig classes meegeven. Wat als je meer dan 1 type database-engine gebruikt, of een Master/Slave-setup?
Dat zijn absoluut geen argumenten om de database class als Singleton te implementeren. Volgens mij haal je een aantal dingen door elkaar. Je geeft niet een db-connectie door aan tig classes, maar een reference naar die connectie zoals die in die db-class gedefinieerd staat al dan niet static ; en let wel.. een method static declareren heeft ook weer vrij weinig te maken met het Singleton pattern.) Het enige verschil is dat je in plaats het doorgeven van een reference naar een db-link overal een getInstance doet.

Daarnaast: meer dan 1 type database engine -> dat los je dus op door dat te encapsulaten in een database class.. niet door een Singleton te implementeren. Zie bijvoorbeeld AdobDB voor hoe zij dat gedaan hebben. :)

Gezien de eigenlijke bedoeling van een Singleton, vind ik het gebruik ervan hier onnodig, maar goed PHP en OO vind ik nog steeds ook een beetje krom in elkaar zitten. ;)
Ga je voor elke database die connectie meegeven?
Als je een getInstance doet, doe je more or less precies hetzelfde.
Het is handiger om dit via een Singleton te regelen. Zo wordt elke database ook maar 1 keer aangeroepen en kan elke class/method zelf bepalen welke connectie die gebruikt.
Nogmaals, dit heeft niks met het hele Singleton pattern van doen 8)7
MindStorm schreef op woensdag 30 mei 2007 @ 20:34:
Ik wil inderdaad het singleton pattern implementeren, omdat ik gemakkelijk steeds van dezelfde databaseconnectie wil maken binnen dezelfde request scope.
Zeg deze zin eens tien keer hard op en probeer mij dan uit te leggen hoe je die bedoelt. ;)

Sundown Circus


Acties:
  • 0 Henk 'm!

  • zwippie
  • Registratie: Mei 2003
  • Niet online

zwippie

Electrons at work

Ik wil niet topickapen maar zit nog met een vraag over het gebruik van singletons. :)

Stel dat je een frontend controller hebt, een single point of entry voor je webapplicatie. In die controller maak je bijvoorbeeld een (is ie weer) DB object aan.
Als je vervolgens strict OO bezig gaat, is het inderdaad niet erg veel moeite om steeds een referentie naar het DB object mee te geven aan elk nieuw object dat de db nodig heeft.
Maar wat als je ook een php bestand gaat includen dat geen klasse is, maar gewoon een dom stuk code wat uitgevoerd moet worden? Globals? Zou kunnen, maar globals hebben ook hun nadelen; het begrijpen en hergebruiken van code met globals kan nogal tricky worden.

PHP dwingt niet tot strict OOP (kan niet eens), dus in de praktijk doe je beide: klasses maken en domme files includen.

Naja. Beide methodes hebben hun voors en hun tegens.
Persoonlijk ben ik wel gecharmeerd van een methode waarbij je voor een webapplicatie eigenlijk maar één (global of singleton) class hebt die fungeert als 'kapstok' voor de rest van je applicatie. Aan die kapstok hang je de db, configs etc. Zo heb je altijd genoeg aan 1 referentie naar iets, hoe je die ook beschikbaar maakt.

offtopic:
De laatse tijd ben ik vrij veel aan het werken met het CodeIgniter framework. Daar heb ik eerlijk gezegd een deel van deze ideeën en ook de (niet helemaal juist gebleken) code die ik eerder postte. Of die code zo is by design, by stupidity of door een fout van mij weet ik niet. Verder zit CodeIgniter erg leuk in elkaar, het brengt behoorlijk wat structuur aan maar werkt niet al te dwingend.[/spam]
En als je wilt kun je er áltijd nog wel spaghetti code van maken. :p

How much can you compute with the "ultimate laptop" with 1 kg of mass and 1 liter of volume? Answer: not more than 10^51 operations per second on not more than 10^32 bits.


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Bedenk je wel dat die kapstok of een Singleton ook gewoon een verkapte global is. Veel nadelen die je bij 'normale' globals hebt heb je hier niet, dat is wel zo, maar je moet er toch op zo'n manier tegenaan kijken. Globals hoeven trouwens helemaal niet 'evil' te zijn, als je ze heel beperkt met streng beleid gebruikt.

Overigens geef ik zelf nooit referenties mee naar DB objecten. Ik heb dit zelf wel achter een static class verwerkt. Aangezien ik op allerlei verschillende plaatsen deze nodig heb, leek dit mij de beste oplossing. Ik heb er nog geen echte nadelen van ondervonden, misschien moeten die nog komen.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • Ciqniz
  • Registratie: Oktober 2002
  • Laatst online: 07-09-2023

Ciqniz

On the move...

Michali schreef op vrijdag 01 juni 2007 @ 10:08:
Bedenk je wel dat die kapstok of een Singleton ook gewoon een verkapte global is. Veel nadelen die je bij 'normale' globals hebt heb je hier niet, dat is wel zo, maar je moet er toch op zo'n manier tegenaan kijken. Globals hoeven trouwens helemaal niet 'evil' te zijn, als je ze heel beperkt met streng beleid gebruikt.

Overigens geef ik zelf nooit referenties mee naar DB objecten. Ik heb dit zelf wel achter een static class verwerkt. Aangezien ik op allerlei verschillende plaatsen deze nodig heb, leek dit mij de beste oplossing. Ik heb er nog geen echte nadelen van ondervonden, misschien moeten die nog komen.
Hoe heb jij dat verder opgelost dan?
Hoe kijk jij of er al een verbinding is met de Db? Of ga je er vanuit dat deze gemaakt is (en doe je dit dus afzonderlijk). Hoe zien jouw methodes er uit bijvoorbeeld? Ben ik wel benieuwd naar...

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Ik heb het nu zo ongeveer:
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
55
56
57
58
59
60
61
62
63
64
65
<?php

interface DBDriver
{
    public function query($query);
    
    public function escape($string);
}

interface DBDriverFactory
{
    public function createDBDriver();
}

class MySQLDBDriver implements DBDriver
{
    public function __construct($username, $password, $dbName)
    {
        // connect
    }
    
    // implementatie van de functies
}

class MySQLDBDriverFactory implements DBDriverFactory
{
    public function createDBDriver()
    {
        return new MySQLDBDriver(
            MYSQL_USERNAME,
            MYSQL_PASSWORD,
            MYSQL_DATABASE
        );
    }
}

class Database
{
    private static $driver;
    
    private static function getDriver()
    {
        if ( is_null(self::$driver) )
        {
            $factoryClass = DB_DRIVER_FACTORY_CLASS;
            $factory = new $factoryClass();
            self::$driver = $factory->createDBDriver();
        }
        return self::$driver;
    }
    
    private function __construct() { }
    
    public static function query($query)
    {
        return self::getDriver()->query($query);
    }
    
    public static function escape($string)
    {
        return self::getDriver()->escape($string);
    }
}

?>


Voordelen:
- Connectie wordt gemaakt als de database voor het eerst gebruikt wordt.
- Ik hoef niet naar de connectie om te kijken.

Nadelen:
- Maar 1 connectie mogelijk, makkelijk switchen tussen DB's zit er niet bij.
- Wisselen van driver is niet mogelijk.

Aangezien ik in mijn apps. altijd met 1 DB werkt, is dit vooralsnog voldoende. Als ik tegen een probleem aan ga lopen, dan ga ik het misschien wel wijzigen zodat deze nadelen niet meer bestaan. Ik begrijp best dat dit voor sommige mensen niet lekker werkt zo, maar voor wat ik nodig heb is het voldoende.

Noushka's Magnificent Dream | Unity

Pagina: 1