Verder met PHP

Door josvane op dinsdag 7 augustus 2012 00:07 - Reacties (13)
Categorie: -, Views: 6.586

Naar aanleiding van mijn vorige post Seo vriendelijk met PHP heb ik een boek gekocht, en wel deze. link

Tegerlijkertijd heb ik mij ook verdiept in PDO, wat met onder andere met het prepare statement een hoop doet om sql injecties e.d. te voorkomen.

In de vorige post werd ik gewezen op het gebruik van globals (in negatieve zin), een zoektocht op internet met gevolg. De 1e opzet heb ik inmiddels werkend. Voor mij gevoel is de aanroep naar de DB goed. De connectie wordt eenmalig opgebouwd e.d.

De query's kan ik volgens mij beter, alleen vindt ik daar verschillende meningen over en niet alle varianten krijg ik werkend.

Vanuit de testFunction wordt de connectie met de DB gemaakt. Vervolgens moet ik de gehele query ook naar de Database class sturen, vervolgens zou ik eigenlijk al extra waardes mee moeten zenden om een verschil te kunnen maken tussen single row of een array.

Eigenlijk wil ik de query en de prepare statement in de testFunction zelf houden, of is dit de beste manier en moet ik inderdaad dit zo laten. Graag jullie mening daarover of wellicht een oplossing. Als dit met een bepaalde php term op te lossen is hoor ik die graag, dan ik daarop verder zoeken.

Waarom een blog en geen topic
De reden dat ik het in een blog plaats is omdat het een vervolg is op mijn vorige topic, en ik een blog uiteindelijk beter vindt voor kennisdeling



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
66
67
68
69
70
71
72
73
<?php
// Example of a Singleton Database class
class Database
{
    // Store the single instance of Database
    private static $m_pInstance;
    private $db_con;

    // Private constructor to limit object instantiation to within the class
    private function __construct() 
    { 
        $DBserver       = 'localhost';
        $DBusername         = 'username';
        $DBpassword     = 'password';
        $DBdatabase     = 'database';
        
        try
        {
            $this->db_con = new PDO('mysql:host='. $DBserver . ';dbname=' . $DBdatabase . ';charset=UTF-8', $DBusername, $DBpassword);
            $this->db_con->setAttribute(PDO::ATTR_PERSISTENT, true);
            $this->db_con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        catch ( PDOException $e ) 
        {
            print "Error!: " . $e->getMessage () . "\n" ;
            die () ;
        }
    }

    // Getter method for creating/returning the single instance of this class
    public static function getInstance()
    {
        if (!self::$m_pInstance)
        {
            self::$m_pInstance = new Database();
        }

        return self::$m_pInstance;
    }
    
    // Test function to simulate a query
    public function query($query)
    {
        $statement = $this->db_con->prepare($query);
        $statement->execute();
        $row = $statement->fetch(); // Use fetchAll() if you want all results, or just iterate over the statement, since it implements Iterator
        return $row;
    }
    
}

// Wrap the test code in a function 
class user
{
    function testFunction()
    {
        // Get the single instance of the Database class using the gettor 
        // method we created.  Then call it's query method to output some text
        $db = Database::getInstance();
        print '<pre>';
        print_r($db->query("select * from jstl_cms_menu where is_link = '1'"));
        print '</pre>';
    }
}

// Start the test
$user = new user();
$user->testFunction();

// After running this script you will see that the constructor was only called
// once, showing that only one instance of the class was created.

?>

Volgende: Omschakelen van Windows naar Mac 10-'12 Omschakelen van Windows naar Mac
Volgende: seo vriendelijk met PHP 06-'12 seo vriendelijk met PHP

Reacties


Door Tweakers user Damic, dinsdag 7 augustus 2012 00:25

Voor de db class zou ik eens zien naar phpbb 3.x of andere moderne forum soft. Ik maak gretig gebruik van hun classes en dat werkt wel goed.

Door Tweakers user josvane, dinsdag 7 augustus 2012 00:26

Alleen maakt Phpbb juist gebruik van globals. Daarnaast wil ik er meer van snappen dan zomaar kopieeren.

Door Tweakers user kokx, dinsdag 7 augustus 2012 00:56

Waarom gebruik je eigenlijk een singleton voor de database? Een database is juist een class waarvan je meerdere instances rond zou kunnen hebben zwerven. Er zijn redelijk wat toepassingen waar je twee (of meer) database connecties wilt hebben. En de configuratie zou ik ook buiten de class plaatsen (ergens in een config bestand).

Over je vraag: Ik zou zeker de hele $db->prepare() en dergelijke in de testFunction() laten. Op deze manier moet je altijd op dezelfde manier werken. Iniedergeval zou ik de fetch statement er zeker uithalen, en het statement object zelf returnen. Anders zit je qua reusability vast aan dezelfde methode, wat echt niet handig is.

Als ik jou was, zou ik trouwens eens rond kijken naar wat voor DB libraries er bestaan. Je kan bijvoorbeeld naar Doctrine kijken. Of naar een framework zoals Zend Framework, of Symfony.

Door Tweakers user curvemod, dinsdag 7 augustus 2012 06:12

Ik zou inderdaad ook voor en bestaande class gaan, al kan ik het me voorstellen dat je zelf een keer een database class wilt designen.

De bovengenoemde projecten zijn allemaal erg groot, dat zijn echt complete ORM's. Ik zou voor een database abstraction layor gaan zoals Doctrine DBAL (http://www.doctrine-project.org/projects/dbal.html).

Om dat heel makkelijk te integreren zou ik Composer gebruiken (getcomposer.org) dan kan hoef je niet meer na te denken over allerlei depedencies. Voor in de composer.json file: {"require": {"doctrine/dbal": "2.2.2"}}

Ik denk dat, als je die tools in je project bouwt, dat je dan echt weer een stap kan maken.

[Reactie gewijzigd op dinsdag 7 augustus 2012 06:16]


Door Tweakers user josvane, dinsdag 7 augustus 2012 08:24

Ik ben erg zoekende naar een goed systeem, een eerder project heb ik gebouwd met pear en DB. Bij mijn hoster werkt het perfect, alleen blijkt met name de module DB niet overal beschikbaar te zijn. Ik wil daarom eigenlijk geen gebruik meer maken hiervan.

Naar doctrine heb ik gekeken alleen heb ik 1 depencies en dat is dan doctrine zelf, PDO is standaard aanwezig.

Pdo heeft daarnaast een duidelijkere notatie mijn inziens.

Door Tweakers user phex, dinsdag 7 augustus 2012 11:00

Voor iemand die gewoon wat met php wil spelen in Doctrine zware overkil. Plus je moet gewoon eerst een paar keer hard onderuit gaan bij het schrijven van je eigen classes zo uit de losse pols. Hierdoor word je geconfronteerd met je eigen design fouten. Zodoende snap je bepaalde design keuzes en wordt je eigen code ook beter. Zo lang je niet voor een productie omgeving aan het schrijven bent is het geen zonde om gewoon weer bij het begin af aan te beginnen.

Echter wat jij als argument geeft om het niet te gebruiken (dependency) is natuurlijk onzin. Je bent niet verplicht om PEAR te gebruiken, en als het gewoon een verzameling losse files zijn is jouw code dan technisch ook een dependency van zichzelf.

Als laatste raad ik je aan om niet alles zelf te schrijven op het moment dat je voor iets serieus aan de slag gaat. Dan kom je er bijvoorbeeld achter dat een heel klein denk foutje in een niet belangrijke functie opeens er voor zorgt dat je hele systeem niet flexibel is en dat je basically alles kan gaan aanpassen.

Als je een paar van dat soort iteraties gehad hebt dan ga je grijpen naar standaard oplossingen. En ik weet dat dat niet spannend is en dat jij dat als enige van de wereld niet gaat overkomen, maar ik zeg het toch nog maar even ter overvloede.

Door Tweakers user josvane, dinsdag 7 augustus 2012 11:55

Okey, het zijn reacties waar ik wat aan heb, maar in het huidige voorbeeld kom ik niet verder.

Hoe kan ik nou query in de testfunctie houden?

Door Tweakers user Zeebonk, dinsdag 7 augustus 2012 12:06

Voor mij is je vraag niet helemaal duidelijk. Heb je verhaal meerdere keren proberen te lezen en het blijft onduidelijk wat je nu precies wilt.

Hoe kan ik nou query in de testfunctie houden?
Er staat nu toch een query in de testfunctie?

Eigenlijk wil ik de query en de prepare statement in de testFunction zelf houden, of is dit de beste manier en moet ik inderdaad dit zo laten.
De "of" zou twee verschillende dingen moeten scheiden, maar de queries staan er al dus als je het "zo zal laten" blijft dit ook zo?

Door Tweakers user Johnny, dinsdag 7 augustus 2012 12:11

Als je op zoek bent naar een simpele ORM voor PHP met PDO-ondersteuning voor MySQL en diverse andere databases moet je eens kijken naar Redbean PHP http://redbeanphp.com

Het heeft een heel simpele API, en je hoeft maar ťťn bestand te includen en kan dan heel snel met weinig regels code met een database communiceren.

Door Tweakers user josvane, dinsdag 7 augustus 2012 12:29

@Zeebonk, ik vindt het idd lastig om mijn vraag duidelijk te maken. Ik zal het nogmaals proberen.

Ik ga het anders proberen te formuleren. Ik zal uiteen zetten wat ik wil en waarom ik denk dat het zo moeten.

class database
De verbinding wordt centraal gelegd en door de instance maar 1x naar die specifieke database. In het voorbeeld staat de config er nog in, dit wordt verplaatst naar een config file

testFunction
Vanuit de testfunction wil ik alle querys naar de database doen. Dit wil ik hier houden om dat juist deze weer variabel zijn. Soms haal je alleen een gebruikersnaam uit de database een andere keer 30 regels. Dan moet ik dus allemaal variabelen mee sturen naar database::query()

Mijn gedachten was om dit te doen

PHP:
1
2
3
4
5
6
function testFunction()
{
$db = Database::getInstance();
$db->prepare("select * from jst");
$db->excute();
}


Dan krijg ik een fout dat prepare statement niet bestaat, wat logisch is. Concreet is dus mijn vraag hoe dit wel kan werken.

edit:

Even los van het feit dat ik gebruik maak van singleton, zou ik dit probleem ook hebben bij een gewoon database connectie maken. Je ziet bijvoorbeeld bij PHPBB dat die gebruik maakt van global. Ik ben dus opzoek naar een alternatief hiervoor

[Reactie gewijzigd op dinsdag 7 augustus 2012 12:32]


Door Tweakers user phex, dinsdag 7 augustus 2012 12:52

Niet getest, werkt waarschijnlijk niet aangezien ik niet met pdo werk, maar puur als een ideetje:


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
abstract class BaseModel {
    protected $connection;
    private abstract function getInstance();
    
    private function getConnection() {
        
        if (!($this->connection instanceof PDO)) {
            $this->connection = new PDO(
                    'mysql:host=' . Settings::getInstance()->data($this->getInstance(), 'hostname') . ';dbname=' . Settings::getInstance()->data($this->getInstance(), 'database') . ';charset=UTF-8', 
                    Settings::getInstance()->data($this->getInstance(), 'username'), 
                    Settings::getInstance()->data($this->getInstance(), 'password')
            );
        }
        return $this->connection;
    }
    
    private function getData($statement, $params = array()) {
        $db = $this->getConnection();
        $db->prepare($statement);
        
        foreach ($params as $field => $value) {
            $db->bindParam(':' . $field, $value);
        }
        
        // RETURN OBJECT/ARRAY/JSON/XML
        
    }
}

class User extends BaseModel {
    private function getInstance() {
        return 'database1';
    }
    
    public function getByEmail($email) {
        return $this->getData('SELECT * FROM users WHERE email = :email', array('email'=> $email));
    }
}

$user = new User();
$person = $user->getByEmail('email@domain.com');


Door Tweakers user sfranken, dinsdag 7 augustus 2012 19:13

Je weet dat dit ook kan he:


code:
1
die("Error!");


Door Tweakers user curvemod, woensdag 8 augustus 2012 00:09

phex schreef op dinsdag 07 augustus 2012 @ 11:00:
Voor iemand die gewoon wat met php wil spelen in Doctrine zware overkil. Plus je moet gewoon eerst een paar keer hard onderuit gaan bij het schrijven van je eigen classes zo uit de losse pols.
Ik heb het over de Doctrine DBAL, dat is iets anders als Doctrine. Ik zie dat als een extensie op PDO, hoop missende features. Ik ben het met je eens dat je dat misschien zelf wel gedaan moet hebben, maar kijk dan in ieder geval naar de code van die tool. En dan dependency verhaal is echt onzin, je kan met Composer die source zo van github halen en dan hoef je alleen 1 autoload file te includen, makkelijker kan bijna niet.

Reageren is niet meer mogelijk