Toon posts:

[PHP] Object geörienteerd - database select

Pagina: 1 2 Laatste
Acties:

Vraag


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik ben sinds vorige week gestart met het leren van object georiënteerd programmeren in PHP.
Gisteren heb ik een klein stukje geprobeerd om alle studentnummers te selecteren.
De code werkt, alleen was ik benieuwd of dit ook de juiste manier is?
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
<?php

class connection{
    private $host='localhost', $user='user', $pass='pass';
    protected $db;
    
    public function __construct(){
        $this->db = mysqli_connect($this->host, $this->user, $this->pass, 'student');
        
        if(mysqli_connect_errno()){
            echo 'Connect failed.';
            exit();
        }
        else{
            echo 'Connectie geslaagd.';
        }
    }
}

class student extends connection{
    private $query;
    public $data;
    
    public function get_students(){
        $this->query = mysqli_query($this->db, "SELECT * FROM student;");
        
        if(mysqli_error($this->db)){
            echo 'Query failed';
        }
        else{
            echo 'Connectie succeed';
            $this->data = mysqli_fetch_assoc($this->query);
            return $this->query;
        }
    }
}


$student = new student();
$students = $student->get_students();
while ($data = mysqli_fetch_assoc($students)){
    echo $data['studentnummer'].'<br>';
}

?>

Alle reacties


Acties:
  • +1 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 23:46
Eerste vraag. Waarom doe je in "get_students" zowel een mysqli_fetch_assoc en stuur je ook de $this->query terug? Met die public $data doe je in je voorbeeld nu niks.

En wat als je later een methode get_students_by_id krijgt? Gebruikt die dan ook de private $query? En weet je dan zeker dat je de juiste $this->query teruggeeft met get_students? Of is dat dan de get_students_by_id $this->query?

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • +1 Henk 'm!

Verwijderd

Let ook op je naamgeving. Jouw $this->query is het resultaat van mysqli_query(...), en die geeft geen query terug maar mysqli_result object - $this->result zou dus een minder verwarrende naam zijn.

Idem voor get_students(), want die geeft geen students terug. Als je in die functie een array van records op zou bouwen wel, bijvoorbeeld.

Tenslotte moet je nog even wat doen met de situatie dat in regel 27 een error optreedt, want nu return je niks, maar ga je er in regel 41 vrolijk van uit dat alles okay is.

Acties:
  • +1 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Maak een instantie van "connection" en geef die mee aan de construct van "student", anders ga je voor iedere instantie een nieuwe connectie maken met je database ipv dat je degene die je hebt hergebruikt. Verder sluit ik me aan bij CurlyMo, waarom de query twee keer uitvoeren? :)

offtopic:
Overigens zou ik gewoon Doctrine DBAL pakken zelf maar misschien iets te hoog gegrepen daarmee te werken en sluit niet helemaal aan bij wat de TS wil nog.

[ Voor 9% gewijzigd door Cartman! op 06-11-2016 16:43 ]


Acties:
  • +1 Henk 'm!

  • kluyze
  • Registratie: Augustus 2004
  • Niet online
Wat jij nu zegt met de overerving is dat een Student een Connection is, dus die lopen door de campus en halen data op uit een database. OO overerving is niet om iets makkelijk te maken, maar om een logische object structuur te creëren.

Bv.
Je hebt een class 'Person', deze class heeft een property 'name' en 'sex'. Je 'Student' class kan dan overerven van deze class en een extra property 'studentnr' definiëren. Je kan dan elke 'Student' ook als een 'Person' behandelen. Later kan dan een 'Employee' class ook overerven van een 'Person' waardoor deze ook automatisch een 'name' en 'sex' property krijgt. Alle gemeenschappelijke properties tussen een 'Employee' en een 'Student' die van hun een 'Person' maken heb je dan op 1 plaats gedefinieerd, namelijk in de 'Person' class.

Een Connection class heeft helemaal niets met een Student te maken en het is vreemd dat een Student overerft van een Connection

Acties:
  • +1 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Montaner
  • Registratie: Januari 2005
  • Laatst online: 13:14
Maak het connection object global zodat je niet telkens opnieuw connect. En gebruik hem daarna in je andere classes om te querien.

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

trix0r schreef op maandag 07 november 2016 @ 10:38:
Maak het connection object global zodat je niet telkens opnieuw connect. En gebruik hem daarna in je andere classes om te querien.
Global? Bah. ;)

Ik zou (in een dergelijke simpele opzet) eerder aan een singleton denken zodat je je global namespace niet verder vervuilt dan nodig.

[ Voor 4% gewijzigd door NMe op 07-11-2016 11:17 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
NMe schreef op maandag 07 november 2016 @ 11:17:
[...]

Global? Bah. ;)

Ik zou (in een dergelijke simpele opzet) eerder aan een singleton denken zodat je je global namespace niet verder vervuilt dan nodig.
Met zijn huidige manier (connection klasse overerven), zou hij het ook gewoon statisch kunnen maken. Geen nette oplossing, maar dat is singleton ook niet.

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

ThomasG schreef op maandag 07 november 2016 @ 12:44:
[...]
Met zijn huidige manier (connection klasse overerven), zou hij het ook gewoon statisch kunnen maken. Geen nette oplossing, maar dat is singleton ook niet.
Klopt, daarom zette ik in mijn edit het stukje tussen haakjes er even bij. :P Er zijn betere oplossingen maar dat leek me hier een beetje buiten scope. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 08-10 23:48

Ventieldopje

I'm not your pal, mate!

DI is hier toch simpel toe te passen? Zeker in zoiets simpels :)

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Ventieldopje schreef op maandag 07 november 2016 @ 13:39:
DI is hier toch simpel toe te passen? Zeker in zoiets simpels :)
Dependency injection aanraden aan iemand die net een weekje bezig is met het concept van OO lijkt me nou niet echt een goed idee.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 08-10 23:48

Ventieldopje

I'm not your pal, mate!

Singleton en globals wel? :Y) Brr.

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Acties:
  • +2 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Globals sowieso niet. :P Singletons zijn op zich zo'n beetje het eerste design pattern dat je leert en vond ik daarmee nog wel veilig om aan te raden. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Bedankt voor jullie reacties!
De dubbele mysqli_fetch_assoc was een foutje.

Ik heb de code aangepast a.d.h.v. jullie reacties, en op dit moment werkend.
Zal dit meer in de richting komen?

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
<?php

class connection{
    private $host='localhost', $user='user', $pass='pass';
    public $db;
    
    public function get_connection(){
        $this->db = mysqli_connect($this->host, $this->user, $this->pass, 'student');
        
        if(mysqli_connect_errno()){
            return false;
        }
        else{
            return $this->db;
        }
    }
}

class student{
    private $query;
    private $r;
    private $_db;
    public $rows;
    
    public function __construct($db){
        $this->_db = $db;
    }
    
    public function get_students(){
        $this->result = mysqli_query($this->_db, "SELECT * FROM student;");
        
        if(mysqli_error($this->_db)){
            return false;           
        }
        else{
            echo 'Connectie succeed';
            $this->rows = array();
            while($this->r = mysqli_fetch_assoc($this->result)) {
                $this->rows[$this->r['studentnummer']] = $this->r['voornaam'];
            }
            return $this->rows;
        }
    }
}

$db = new connection;
$dbcon = $db->get_connection();

if(!$dbcon){
    echo 'Er is een fout met de verbinding met de database!';
}
else{
    $student = new student($dbcon);
    $students = $student->get_students();
    
    if(!$students){
        echo 'Studenten konden niet worden opgehaald!';
    }
    else{
        print_r($students);
    }
}
?>

Acties:
  • +1 Henk 'm!

  • Gamebuster
  • Registratie: Juli 2007
  • Laatst online: 27-09 22:01
NMe schreef op maandag 07 november 2016 @ 11:17:
[...]

Global? Bah. ;)

Ik zou (in een dergelijke simpele opzet) eerder aan een singleton denken zodat je je global namespace niet verder vervuilt dan nodig.
Een singleton is gewoon een global verpakt in een strikje

[ Voor 8% gewijzigd door Gamebuster op 07-11-2016 15:31 ]

Let op: Mijn post bevat meningen, aannames of onwaarheden


Acties:
  • +1 Henk 'm!

  • Standeman
  • Registratie: November 2000
  • Laatst online: 20:10

Standeman

Prutser 1e klasse

Verwijderd schreef op maandag 07 november 2016 @ 15:29:
Bedankt voor jullie reacties!
De dubbele mysqli_fetch_assoc was een foutje.

Ik heb de code aangepast a.d.h.v. jullie reacties, en op dit moment werkend.
Zal dit meer in de richting komen?

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
<?php

class connection{
    private $host='localhost', $user='user', $pass='pass';
    public $db;
    
    public function get_connection(){
        $this->db = mysqli_connect($this->host, $this->user, $this->pass, 'student');
        
        if(mysqli_connect_errno()){
            return false;
        }
        else{
            return $this->db;
        }
    }
}

class student{
    private $query;
    private $r;
    private $_db;
    public $rows;
    
    public function __construct($db){
        $this->_db = $db;
    }
    
    public function get_students(){
        $this->result = mysqli_query($this->_db, "SELECT * FROM student;");
        
        if(mysqli_error($this->_db)){
            return false;           
        }
        else{
            echo 'Connectie succeed';
            $this->rows = array();
            while($this->r = mysqli_fetch_assoc($this->result)) {
                $this->rows[$this->r['studentnummer']] = $this->r['voornaam'];
            }
            return $this->rows;
        }
    }
}

$db = new connection;
$dbcon = $db->get_connection();

if(!$dbcon){
    echo 'Er is een fout met de verbinding met de database!';
}
else{
    $student = new student($dbcon);
    $students = $student->get_students();
    
    if(!$students){
        echo 'Studenten konden niet worden opgehaald!';
    }
    else{
        print_r($students);
    }
}
?>
Wat over het algemeen ook netjes is binnen OO is zogenaamde de single responsibillty principle. In principe heeft een student niets met queries, SQL of databases te maken. Wat je kan doen is alle SQL gerelateerde code in de aparte 'DAO' te zetten (Data Acces Object). Zie ook Wikipedia: Data access object

The ships hung in the sky in much the same way that bricks don’t.


Acties:
  • +1 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 23:46
Je kan ook nog proberen om de get_students 'loopbaar' te maken zodat je zoiets kan doen:
PHP:
1
2
3
while($students = $student->get_students()) {
   ...
}


Nu haal je alle studenten al op terwijl je misschien maar iets doet met een subset ervan.

Een andere optie is het faciliteren van een limit en offset zodat je altijd maar bijv. 100 studenten per keer ophaalt.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Waarom maak je geen gebruik van Doctrine?

Acties:
  • +1 Henk 'm!

  • Standeman
  • Registratie: November 2000
  • Laatst online: 20:10

Standeman

Prutser 1e klasse

4Real schreef op maandag 07 november 2016 @ 16:05:
Waarom maak je geen gebruik van Doctrine?
Voornamelijk om OO concepten wat meer te doorgronden. Het gaat niet om het doel, het gaat om de reis ;)

The ships hung in the sky in much the same way that bricks don’t.


Acties:
  • +1 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Ik zou een StudentRepository aanmaken waar het gehele database verkeer in afgehandeld wordt. Daarin wordt de class Student gevuld, door bijvoorbeeld een RecordToStudentMapper.

Dan krijg je iets als het volgende:
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
class Student
{
    public $ID;
    public $Naam;
}

class StudentRepository
{
    private $_conn
    public function __construct($conn)
    {
        $this->_conn = $conn;
    }

    public function FindAll()
    {
        $query = "select * from student;";

        // handel query shit af

        $mapper = new RecordToStudentMapper();

        $outputList = array()
        foreach($records as $record)
        {
            $student = new Student;
            $mapper->Map($record, $student);
            $outputList[] = $student;
        }

        return $outputList;
    }

    public function Save($student)
    {
        // handel hier insert en update af
    }
}

class RecordToStudentMapper
{
    public function Map($record, $student)
    {
        $student->ID = $record['ID'];
        $student->Naam = $record['Naam'];
    }
}


In de StudentRepository kun je nog bijhouden of een record bestaat in de database, zodat je weet of je een insert of update moet uitvoeren. Volgens mij kun je hiervoor een UnitOfWork class introduceren, maar dan ga je al snel de overkill kant op :)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
4Real schreef op maandag 07 november 2016 @ 16:31:
Ik zou een StudentRepository aanmaken waar het gehele database verkeer in afgehandeld wordt. Daarin wordt de class Student gevuld, door bijvoorbeeld een RecordToStudentMapper.

Dan krijg je iets als het volgende:
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
class Student
{
    public $ID;
    public $Naam;
}

class StudentRepository
{
    private $_conn
    public function __construct($conn)
    {
        $this->_conn = $conn;
    }

    public function FindAll()
    {
        $query = "select * from student;";

        // handel query shit af

        $mapper = new RecordToStudentMapper();

        $outputList = array()
        foreach($records as $record)
        {
            $student = new Student;
            $mapper->Map($record, $student);
            $outputList[] = $student;
        }

        return $outputList;
    }

    public function Save($student)
    {
        // handel hier insert en update af
    }
}

class RecordToStudentMapper
{
    public function Map($record, $student)
    {
        $student->ID = $record['ID'];
        $student->Naam = $record['Naam'];
    }
}


In de StudentRepository kun je nog bijhouden of een record bestaat in de database, zodat je weet of je een insert of update moet uitvoeren. Volgens mij kun je hiervoor een UnitOfWork class introduceren, maar dan ga je al snel de overkill kant op :)
Bedankt, ik heb nu het volgende:
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
<?php
class connection{
    private $host='localhost', $user='user', $pass='pass';
    public $db;
    
    public function get_connection(){
        $this->db = mysqli_connect($this->host, $this->user, $this->pass, 'student');
        
        if(mysqli_connect_errno()){
            return false;
        }
        else{
            return $this->db;
        }
    }
}
class Student
{
    public $ID;
    public $Naam;
}

class StudentRepository
{
    private $_conn;
    public $result;
    public function __construct($conn)
    {
        $this->_conn = $conn;
    }

    public function FindAll()
    {
        $this->result = mysqli_query($this->_conn, "select * from student;");

        

        $mapper = new RecordToStudentMapper();

        $outputList = array();
        while($record = mysqli_fetch_assoc($this->result))
        {
            $student = new Student;
            $mapper->Map($record, $student);
            $outputList[] = $student;
        }

        return $outputList;
    }

    public function Save($student)
    {
        // handel hier insert en update af
    }
}

class RecordToStudentMapper
{
    public function Map($record, $student)
    {
        $student->ID = $record['studentnummer'];
        $student->Naam = $record['voornaam'];
    }
}

$db = new connection;
$dbcon = $db->get_connection();
$student = new StudentRepository($dbcon);
$students = $student->FindAll();
print_r($students);
?>


En stel ik wil dit nu ook doen voor vakken, dan zou ik dus ook 3 van deze classes moeten maken (m.u.v. connection uiteraard).

Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Yup,

Kun je trouwens de toelichten waarom je het musali resultaat in een public variabel opslaat?

En de database class. Zie daar vanaf en stap over naar PDO (zie php.net daarover). Lees direct in over parametizen van je queries (dikke mist!!!).

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
4Real schreef op maandag 07 november 2016 @ 17:57:
Yup,

Kun je trouwens de toelichten waarom je het musali resultaat in een public variabel opslaat?

En de database class. Zie daar vanaf en stap over naar PDO (zie php.net daarover). Lees direct in over parametizen van je queries (dikke mist!!!).
Dat was niet de bedoeling om dat als public variabele te zetten. Ik het het aangepast naar een private variabele.
:)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb nu PDO gebruikt in plaats van MySQLi, zie onderstaande 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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php
class connection{
    private $db='mysql:host=localhost;dbname=student;port=3307', $user='user', $pass='pass';
    public $pdo;
    
    public function get_connection(){
        try{
            $this->pdo = new PDO($this->db, $this->user, $this->pass);
            return $this->pdo;
        }
        catch (PDOException $err) {
            print("<p class='err'>Er is een fout opgetreden: " . $err->getMessage() . "</p>");
        }
    }
}
class Student
{
    public $ID;
    public $Naam;
}

class StudentRepository
{
    private $_conn;
    private $result;
    public function __construct($conn)
    {
        $this->_conn = $conn;
    }

    public function FindAll()
    {
        $this->result = $this->_conn->prepare("SELECT * FROM student");
        $this->result->execute();

        $mapper = new RecordToStudentMapper();

        $outputList = array();
        while($record = $this->result->fetch())
        {
            $student = new Student;
            $mapper->Map($record, $student);
            $outputList[] = $student;
        }

        return $outputList;
    }

    public function Save($student)
    {
        // handel hier insert en update af
    }
}

class RecordToStudentMapper
{
    public function Map($record, $student)
    {
        $student->ID = $record['studentnummer'];
        $student->Naam = $record['voornaam'];
    }
}

$db = new connection;
$dbcon = $db->get_connection();
$student = new StudentRepository($dbcon);
$students = $student->FindAll();
print_r($students);
?>


De code is getest en werkt!
Is dit ook de juiste methode?
print_r wordt enkel gebruikt om te testen!

[ Voor 1% gewijzigd door Verwijderd op 07-11-2016 18:15 . Reden: toevoeging notitie print_r ]


Acties:
  • +1 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
PDO is al een class, dus zie af van je connection class. Je kan PDO direct in de repository doorgeven.

Nog steeds vind ik het vreemd waarom je $this->result gebruikt. Ga je het resultaat later nog in een andere functie gebruiken? Nu blijft het onnodig in het class (en dus geheugen) bestaan.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
4Real schreef op maandag 07 november 2016 @ 18:17:
PDO is al een class, dus zie af van je connection class. Je kan PDO direct in de repository doorgeven.

Nog steeds vind ik het vreemd waarom je $this->result gebruikt. Ga je het resultaat later nog in een andere functie gebruiken? Nu blijft het onnodig in het class (en dus geheugen) bestaan.
Klopt.
Maar in het geval van meerdere repositoriy's, voor student en voor vakken, zal ik dus ook 2 keer de inloggegevens moeten opslaan, toch? Dat is niet optimaal.

Het resultaat ga ik niet in nog een andere functie gebruiken, hoe stel jij het voor?

[ Voor 7% gewijzigd door Verwijderd op 07-11-2016 18:25 ]


Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Verwijderd schreef op maandag 07 november 2016 @ 18:24:
[...]


Klopt.
Maar in het geval van meerdere repositoriy's, voor student en voor vakken, zal ik dus ook 2 keer de inloggegevens moeten opslaan, toch? Dat is niet optimaal.

Het resultaat ga ik niet in nog een andere functie gebruiken, hoe stel jij het voor?
Je moet het meer als een doorgeef luik zien. Bij je opmerking over "opslaan van inloggegevens" gaan er bij mij al alarm bellen rinkelen, dus dat hoort daar niet thuis!

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Als ik het als een doorgeefluik zie gebeurd dat nu toch?
De class connection geeft de connectie door aan de andere classes?

Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Verwijderd schreef op maandag 07 november 2016 @ 18:29:
Als ik het als een doorgeefluik zie gebeurd dat nu toch?
De class connection geeft de connectie door aan de andere classes?
Volgens mij begrijpen wij elkaar nog niet. Ik doel alleen op $this->result (waar je het resultaat van de query opslaat). Wat wil je daar later nog mee gaan doen?

Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Nog even wat extra waar je over kan nadenken.

Tabel naam in de entiteit (bv, student) opslaan, zodat je deze kunt gebruiken in de repository.
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 Student
{
    const TableName = 'student';
}

// bijvoorbeeld
class EntityRepository
{
    protected $_EntityName;

    public function __construct($entity)
    {
        $this->_EntityName = $entity;

        $class = new ReflectionClass($this->_EntityName);
        $this->_TableName = $class->getConstant('TableName');
    }
    public function FindAll()
    {
        
        $query = sprintf('SELECT * FROM %s;', $this->_TableName);
    }
}

$studentRepository = new EntityRepository('Student');
$studentRepository->FindAll(); // query zal zijn: SELECT * FROM Student

// nu met een nieuwe entiteit
class Adres
{
    const TableName = 'Adres';
}
$adresRepository = new EntityRepository('Adres');
$adresRepository->FindAll(); // query zal zijn: SELECT * FROM Adres


Zo creeer je i.i.g. al een omgeving waar code dat praktisch hetzelfde doet: select * from student/adres/boek bij elkaar zit. Als je dan een aanpassing op FindAll niveau wil doorvoeren, dat hoef je dat maar op één plek te doen.

Echter het resultaat van de query zal overal anders zijn, dus dat meot uit elkaar getrokken worden.
Je kan in je EntityRepository (een soort base class) een functie opnemen:
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 EntityRepository
{
    protected function ExecuteQuery($columns = array(), $limit = 25, $offset = 0)
    {
        $query = sprintf('SELECT %s FROM %s LIMIT %d %d;', join(',', $columns, $this->_EntityName, $limit, $offset);

        // handel hier query gebeuren af

        return mysqli_fetch_assoc($result); // maar liever dan op de PDO manier!!
    }

    public function FindAll()
    {
        $result = $this->ExecuteQuery(array('*'), 999, 0); // of het aan te raden is om max 999 resultaten op te halen valt te betwisten

        // nu moeten wij hier de bende gaan mappen
        // maar we weten niet hoe de class Student er uit ziet
        // dus daar moet nog wat moois voor bedacht worden
        // een optie is om de mapper in de constructor mee te geven

        return $outputList
    }

    // door de executeQuery functie kunnen we ook andere functies makkelijk introduceren
    public function FindBy($criteria = array())
    {
        // voorbeeld van $criteria = array('Oogkleur' => 'Blauw');
        // perform ExecuteQuery, maar dan met de WHERE statement.
        // de functie moet dan uitgebreid worden met de $criteria en de array moet dan in de string terug komen.    

        // spul mappen en teruggeven
    }
}


Nu heb je een Repository voor de algemene zaken, maar stel je wil vaker een bepaalde zoekopdracht uitvoeren.
Ik wil alle student wie linkshandig zijn. Dan wil je niet steeds: FindBy(array('Handedness' => 'Left')); intypen.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
class StudentRepository extends EntityRepository
{
    public function __construct()
    {
        parent::__construct('Student');
    }

    public function GetLefties()
    {
        return $this->FindBy(array('Handedness' => 'Left'));
    }
}


Zo kun je je StudentRepository specialiseren puur voor de entiteit Student. Een handig regels is: StudentRepository geeft alleen Studenten terug!

disclaimer: getypt op de bank in Notepad, dus er kunnen nog syntax fouten inzitten :P

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
4Real schreef op maandag 07 november 2016 @ 18:33:
[...]

Volgens mij begrijpen wij elkaar nog niet. Ik doel alleen op $this->result (waar je het resultaat van de query opslaat). Wat wil je daar later nog mee gaan doen?
Nee, dat wordt later niet meer gebruikt?
En hoe zit het nu met de connection?

[ Voor 5% gewijzigd door Verwijderd op 07-11-2016 18:47 ]


Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Verwijderd schreef op maandag 07 november 2016 @ 18:46:
[...]


Nee, dat wordt later niet meer gebruikt?
En hoe zit het nu met de connection?
Het resultaat wordt later niet meer gebruikt. Dat is alleen nodig voor het vullen van de Student class. Daarna kan het wel weer weg.

De connectie is wel van belang. Je kan namelijk meerdere malen een select query uitvoeren, dus die verbinding naar de database blijft van belang.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
4Real schreef op maandag 07 november 2016 @ 18:52:
[...]
Het resultaat wordt later niet meer gebruikt. Dat is alleen nodig voor het vullen van de Student class. Daarna kan het wel weer weg.

De connectie is wel van belang. Je kan namelijk meerdere malen een select query uitvoeren, dus die verbinding naar de database blijft van belang.
Oké, bedankt! Maar hoe wil hoe wil je dan zonder 'result' gebruik maken van de query?

Met de connectie had ik het echter over:
PDO is al een class, dus zie af van je connection class.

Acties:
  • +1 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Verwijderd schreef op maandag 07 november 2016 @ 18:55:
[...]


Oké, bedankt! Maar hoe wil hoe wil je dan zonder 'result' gebruik maken van de query?
ipv:
PHP:
1
$this->result = $this->db->executeQueryOpPDOmanier();

gebruik je
PHP:
1
$result = $this->db->executeQueryOpPDOmanier();

Zo sla je hem in de scope van de functie op, maar niet op class niveau. De garbage collector zal het geheugen weer opschonen nadat de functie is afgerond.
Met de connectie had ik het echter over:

[...]
PHP:
1
2
3
$pdo = new PDO($param, $param, $param);

$entityRepository = new EntityRepository(\PDO $pdo);


Dat bespaart je weer een class en je drukt het PDO direct in de repository.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
4Real schreef op maandag 07 november 2016 @ 18:59:
[...]
ipv:
PHP:
1
$this->result = $this->db->executeQueryOpPDOmanier();

gebruik je
PHP:
1
$result = $this->db->executeQueryOpPDOmanier();

Zo sla je hem in de scope van de functie op, maar niet op class niveau. De garbage collector zal het geheugen weer opschonen nadat de functie is afgerond.


[...]

PHP:
1
2
3
$pdo = new PDO($param, $param, $param);

$entityRepository = new EntityRepository(\PDO $pdo);


Dat bespaart je weer een class en je drukt het PDO direct in de repository.
Yes, ik begrijp het, dankje!
Ik heb nu de volgende 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
52
53
54
55
56
57
58
59
<?php
class Student
{
    public $ID;
    public $Naam;
}

class StudentRepository
{
    private $_conn;
    public function __construct($conn)
    {
        $this->_conn = $conn;
    }

    public function FindAll()
    {
        $result = $this->_conn->prepare("SELECT * FROM student");
        $result->execute();

        $mapper = new RecordToStudentMapper();

        $outputList = array();
        while($record = $result->fetch())
        {
            $student = new Student;
            $mapper->Map($record, $student);
            $outputList[] = $student;
        }

        return $outputList;
    }

    public function Save($student)
    {
        // handel hier insert en update af
    }
}

class RecordToStudentMapper
{
    public function Map($record, $student)
    {
        $student->ID = $record['studentnummer'];
        $student->Naam = $record['voornaam'];
    }
}

try{
    $pdo = new PDO('mysql:host=localhost;dbname=student;port=3307', 'user', 'pass');
    $student = new StudentRepository($pdo);
    $students = $student->FindAll();
    $pdo = NULL;
    print_r($students);
}
catch (PDOException $err) {
    print("<p class='err'>Er is een fout opgetreden: " . $err->getMessage() . "</p>");
}
?>


Klopt dit, het werkt wel ;).
Ik ga nu naar je andere post kijken

Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Succes! Ik hoor het wel :)

btw, als je wil dat PDO altijd excepties gooit:
PHP:
1
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

Bron: http://php.net/manual/en/pdo.error-handling.php

Acties:
  • +1 Henk 'm!

  • Radiant
  • Registratie: Juli 2003
  • Niet online

Radiant

Certified MS Bob Administrator

Je kan die Mapper ook skippen met PDO als je fetchObject gebruikt.

http://php.net/manual/en/pdostatement.fetchobject.php

Acties:
  • 0 Henk 'm!

  • HollowGamer
  • Registratie: Februari 2009
  • Niet online
Die mapper snap ik niet helemaal, je kunt toch ook gewoon de hele record in een $data variable stoppen?
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
<?php
class Student {
  protected $db = null;
  protected $studentData = [];

  public function __construct(\PDO $db) {
    $this->db = $db;
  }

  // gebruik magic methods, niet het snelste, maar wel zo makkelijk
  public function __set($key, $value) {
    $this->studentData[$key] = $value;
  }

  // Een findAll staat in mijn ogen voor zoeken (bv. vind alle met Achternaam ..)
  public function getAll() {
    $sth = $this->db->prepare("SELECT * FROM student");
    $sth->execute();
    return $sth->fetchAll(); // gebruik zoveel mogelijk ingebouwde functions
  }

  public function set(array $userData) {
    // soms wil je bijvoorbeeld nog wat extra checks/sanitize doen, daarom gebruik ik vaak een set() methode
    $this->studentData = $userData;
  }

  // Het splitten geeft je een meer overzicht; gebruik save() voor update, en insert() voor invoeren van een record
  public function save() {

  }

  public function insert() {
    // $this->studentData..
  }
}

try {
  // Init DB
  $pdo = new PDO('mysql:host=localhost;dbname=student;port=3307', 'user', 'pass');
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

  // Get Students
  $student = new Student($pdo);
  $students = $student->getAll();

  $pdo = NULL;
  print_r($students);
}

catch (PDOException $err) {
    print("<p class='err'>Er is een fout opgetreden: " . $err->getMessage() . "</p>");
}

// geen close tag

Er bestaat btw. geen goed of fout, maar wil je echt 'beter' en eenvoudiger gaan coderen, dan raad ik zeker aan om eens te kijken naar frameworks als Laravel en SlimPHP.

Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
@archie2012, waar je problemen mee gaat krijgen is relaties. Hoe ga je met een één-op-één rerlatie of één-op-meer om? Persoonlijk vind ik het mooier om de entiteit classes zo te schrijven dat ze een weerspiegeling zijn van de werkelijkheid. Het kan misschien wat meer werk zijn als je data model wijzigt, maar dan ontkom je niet aan refactoren, dus dan maar wat meer aanpassingen doorvoeren.

Acties:
  • +1 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 23:46
4Real schreef op maandag 07 november 2016 @ 21:03:
Het kan misschien wat meer werk zijn als je data model wijzigt, maar dan ontkom je niet aan refactoren, dus dan maar wat meer aanpassingen doorvoeren.
Dat kan wel, maar dan moet je naar een ORM gaan kijken. Dat is buiten de scope van dit topic.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • douchekip
  • Registratie: Oktober 2016
  • Laatst online: 04-01-2023
Het mixen van configuratie en code is niet de "netste" manier. Je zou de configuratie (connection string, username, password) als argumenten aan de Connection constructor mee kunnen geven.


In de opzet zoals je het nu hebt is de Connection class een beetje dubbelzinnig.

Wanneer je alleen kijkt naar de code van de class zelf is het echt een "Connection".
Maar verderop in de code gebruik je de Connection instantie alleen voor het maken van een verbinding en gebruik je in het vervolg van je code alleen het resultaat van de get_connection methode en wordt de Connection instantie verwaarloosd. Je gebruikt het dus meer als een soort "ConnectionBuilder".

In een simpel geval als dit zou ik de Connection class achterwege laten, omdat PDO in dit voorbeeld al abstract genoeg is.
Als je wél de Connection class wilt gebruiken (omdat je het wilt leren), zou ik de get_connection niks laten returnen en de Connection instantie zelf 'injecteren' in de StudentRepository. In dit geval kan je er misschien ook over nadenken om de PDO instantie in de Connection class weg te abstracten voor de buitenwereld, d.w.z. de "public $pdo" om te zetten naar een "private/protected $pdo" en een andere manier maken voor de buitenwereld om queries uit te voeren. Gewoon, voor de oefening. :P


p.s. en je kan kijken of je je schrijfwijzes wat consequenter kan krijgen. (UpperCamelCase vs lowerCamelCase vs snake_case en variabelen prefixen met underscores of niet)


p.s.2: Ik had de tweede pagina van dit topic over het hoofd gezien, dus deze reactie lijkt misschien wat out-of-context, maar is een reactie op de laatste post van de eerste pagina 8)7

[ Voor 6% gewijzigd door douchekip op 07-11-2016 21:23 ]


Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
douchekip schreef op maandag 07 november 2016 @ 21:19:
Het mixen van configuratie en code is niet de "netste" manier. Je zou de configuratie (connection string, username, password) als argumenten aan de Connection constructor mee kunnen geven.
Dependency injection ftw! :)

Acties:
  • +1 Henk 'm!

  • incaz
  • Registratie: Augustus 2012
  • Laatst online: 15-11-2022
HollowGamer schreef op maandag 07 november 2016 @ 19:28:

// gebruik magic methods, niet het snelste, maar wel zo makkelijk
public function __set($key, $value) {
$this->studentData[$key] = $value;
}

[/code]
En dan in plaats van $student->id of $student->getId() moet je dat aanroepen met $student->studentData['id']? :N en je ontneemt je IDE de nuttige mogelijkheden, zoals het tonen van de beschikbare functies/properties en het waarschuwen voor fouten. (Er is voor de IDE immers geen mogelijkheid om te weten of de key 'id' bestaat of niet. Maar als je een property 'id' aanmaakt in je class, is het wel duidelijk dat die bestaat - en dat $student->numberOfPets er niet is (en met goede reden.)

Je moet je classes zo maken dat ze vooral representeren waar het om gaat. En dan ook zo voorspelbaar en saai mogelijk zijn: niet hoe je het schrijft is belangrijk, maar hoe jij (en anderen) nu en in de toekomst zouden verwachten dat je een object van die klasse zou gebruiken. (En dan bedoel ik niet dat je nu al moeten weten wat je in de toekomst allemaal nog toe wilt voegen... maar zelfs als het nu nog wel te onthouden lijkt om ->studentData['$key] te gebruiken, zou je dat over een jaar of 4 en 20 applicaties verder nog steeds zo logisch en vanzelfsprekend vinden?)

(En die mappers blijven bestaan, maar ze zijn vanwege het saaie werk goed te automatiseren. Wat dan ook precies is wat ORM (Object-Relational-Mappers, zoals Doctrine2) doen. En als je bv Symfony neemt, hoef je je entity (dus de verzameling properties en relations) maar 1 keer te schrijven, en je gooit er een generator overheen, en je krijgt een class met alle standaard getters en setters. Dan hoef je dus alleen maar de dingen te schrijven die complexer zijn dan dat.)

Never explain with stupidity where malice is a better explanation


Acties:
  • +1 Henk 'm!

  • HollowGamer
  • Registratie: Februari 2009
  • Niet online
incaz schreef op maandag 07 november 2016 @ 21:30:
[...]


En dan in plaats van $student->id of $student->getId() moet je dat aanroepen met $student->studentData['id']? :N en je ontneemt je IDE de nuttige mogelijkheden, zoals het tonen van de beschikbare functies/properties en het waarschuwen voor fouten. (Er is voor de IDE immers geen mogelijkheid om te weten of de key 'id' bestaat of niet. Maar als je een property 'id' aanmaakt in je class, is het wel duidelijk dat die bestaat - en dat $student->numberOfPets er niet is (en met goede reden.)
Daar hebben ze toch de __get method voor uitgevonden?
PHP:
1
2
3
4
5
6
7
8
// In class
public function __get($key) {
   return $this->studentData[$key];
}

// Daarbuiten
echo $student->id;
echo $student->name;

Zou inderdaad nooit data ophalen via de manier die jij beschrijft (e.g. $student->studentData['id']).

[ Voor 10% gewijzigd door HollowGamer op 07-11-2016 21:55 ]


Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
In PHP kom je misschien met dit soort grappen nog weg, maar probeer dit eens in Java of c#. Daarnaast maakt het je code niet echt veel mooier.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
4Real schreef op maandag 07 november 2016 @ 18:38:
Nog even wat extra waar je over kan nadenken.

Tabel naam in de entiteit (bv, student) opslaan, zodat je deze kunt gebruiken in de repository.
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 Student
{
    const TableName = 'student';
}

// bijvoorbeeld
class EntityRepository
{
    protected $_EntityName;

    public function __construct($entity)
    {
        $this->_EntityName = $entity;

        $class = new ReflectionClass($this->_EntityName);
        $this->_TableName = $class->getConstant('TableName');
    }
    public function FindAll()
    {
        
        $query = sprintf('SELECT * FROM %s;', $this->_TableName);
    }
}

$studentRepository = new EntityRepository('Student');
$studentRepository->FindAll(); // query zal zijn: SELECT * FROM Student

// nu met een nieuwe entiteit
class Adres
{
    const TableName = 'Adres';
}
$adresRepository = new EntityRepository('Adres');
$adresRepository->FindAll(); // query zal zijn: SELECT * FROM Adres


Zo creeer je i.i.g. al een omgeving waar code dat praktisch hetzelfde doet: select * from student/adres/boek bij elkaar zit. Als je dan een aanpassing op FindAll niveau wil doorvoeren, dat hoef je dat maar op één plek te doen.

Echter het resultaat van de query zal overal anders zijn, dus dat meot uit elkaar getrokken worden.
Je kan in je EntityRepository (een soort base class) een functie opnemen:
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 EntityRepository
{
    protected function ExecuteQuery($columns = array(), $limit = 25, $offset = 0)
    {
        $query = sprintf('SELECT %s FROM %s LIMIT %d %d;', join(',', $columns, $this->_EntityName, $limit, $offset);

        // handel hier query gebeuren af

        return mysqli_fetch_assoc($result); // maar liever dan op de PDO manier!!
    }

    public function FindAll()
    {
        $result = $this->ExecuteQuery(array('*'), 999, 0); // of het aan te raden is om max 999 resultaten op te halen valt te betwisten

        // nu moeten wij hier de bende gaan mappen
        // maar we weten niet hoe de class Student er uit ziet
        // dus daar moet nog wat moois voor bedacht worden
        // een optie is om de mapper in de constructor mee te geven

        return $outputList
    }

    // door de executeQuery functie kunnen we ook andere functies makkelijk introduceren
    public function FindBy($criteria = array())
    {
        // voorbeeld van $criteria = array('Oogkleur' => 'Blauw');
        // perform ExecuteQuery, maar dan met de WHERE statement.
        // de functie moet dan uitgebreid worden met de $criteria en de array moet dan in de string terug komen.    

        // spul mappen en teruggeven
    }
}


Nu heb je een Repository voor de algemene zaken, maar stel je wil vaker een bepaalde zoekopdracht uitvoeren.
Ik wil alle student wie linkshandig zijn. Dan wil je niet steeds: FindBy(array('Handedness' => 'Left')); intypen.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
class StudentRepository extends EntityRepository
{
    public function __construct()
    {
        parent::__construct('Student');
    }

    public function GetLefties()
    {
        return $this->FindBy(array('Handedness' => 'Left'));
    }
}


Zo kun je je StudentRepository specialiseren puur voor de entiteit Student. Een handig regels is: StudentRepository geeft alleen Studenten terug!

disclaimer: getypt op de bank in Notepad, dus er kunnen nog syntax fouten inzitten :P
Bedankt, maar:
Hoe gebruik ik nu JOINS, of soms meerdere JOINS of subqueries?
Bij voorkeur schrijf ik voor alles de SQL gewoon zelf, daar heb ik geen probleem mee.

[ Voor 210% gewijzigd door Verwijderd op 07-11-2016 23:00 . Reden: Wijziging antwoord, verkeerde reactie + typo ]


Acties:
  • +1 Henk 'm!

  • HollowGamer
  • Registratie: Februari 2009
  • Niet online
SQL joins blijven altijd sneller, wat je echt perse gejoind wilt hebben, doe ik altijd zoveel mogelijk in SQL.

Echter opent OOP mogelijkheden waar je met pure SQL vaak tegen moeilijkheden of ergernissen loopt. Kijk eens naar wat frameworks, de simplicity wat deze bieden is vaak een verademing:
PHP:
1
2
3
4
Class Members {
   use Tags; // om maar een voorbeeld te geven
   use Groups;  // haal bij elke member zijn groepen op, of doe iets anders met groepen
}

Toegeven aan de achterkant zitten queries, maar het gaat erom hoe je deze zo makkelijk mogelijk zou kunnen maken. ;)

[ Voor 11% gewijzigd door HollowGamer op 07-11-2016 23:18 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
HollowGamer schreef op maandag 07 november 2016 @ 23:17:
SQL joins blijven altijd sneller, wat je echt perse gejoind wilt hebben, doe ik altijd zoveel mogelijk in SQL.

Echter opent OOP mogelijkheden waar je met pure SQL vaak tegen moeilijkheden of ergernissen loopt. Kijk eens naar wat frameworks, de simplicity wat deze bieden is vaak een verademing:
PHP:
1
2
3
4
Class Members {
   use Tags; // om maar een voorbeeld te geven
   use Groups;  // haal bij elke member zijn groepen op, of doe iets anders met groepen
}

Toegeven aan de achterkant zitten queries, maar het gaat erom hoe je deze zo makkelijk mogelijk zou kunnen maken. ;)
Eigenlijk hoef je bijvoorbeeld de woorden SELECT, FROM en WHERE niet in te vullen?
Maar het voordeel is dat je de WHERE stukjes, en tabelnaam in PHP gescheiden hebt.
Alleen met JOINS gaat dit dus lastiger worden, waardoor een framework handig is. Maar dan kan ik toch net zo goed gewoon SQL blijven schrijven?

Toevoeging Ik wil eerst ervaring opdoen met OOP en daarna pas gaan kijken naar frameworks.

[ Voor 4% gewijzigd door Verwijderd op 08-11-2016 00:18 ]


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 23:46
Je hoeft je OOP ervaringen ook niet te beginnen met database connecties. Dat kan snel complex worden.
Om te zien waar OOP nog meer wordt gebruikt is het boek Head First Design Patterns een aanrader. Daarnaast leer je verschillende implementatie vormen van OOP kennen waarvan eerder Singleton al is genoemd. Je hoeft nu nog niet alles te begrijpen, dat komt later wel.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • +1 Henk 'm!

  • incaz
  • Registratie: Augustus 2012
  • Laatst online: 15-11-2022
HollowGamer schreef op maandag 07 november 2016 @ 21:50:
Daar hebben ze toch de __get method voor uitgevonden?
Die had je er niet bij gezet.

Maar belangrijker: dat blijft alle nadelen houden die ik noemde: je krijgt als je je object gebruikt geen behulpzame autocomplete-hints als je $student-> typt, en de IDE kan niet waarschuwen voor nietbestaande keys, maar wel voor nietbestaande properties.
Dat PHP allerlei sluiproutes en shortcuts biedt is leuk/fractal of bad design* maar uiteindelijk zijn er mogelijkheden genoeg om met een IDE en een framework gewoon nette en vrij robuste code te schrijven die niet op allerlei momenten runtime foutmeldingen geeft (of foutmeldingen negeert en zelf maar iets creatiefs bedenkt en daarmee verder gaat.)

*doorhalen wat niet van toepassing is

Als je __get en __set wilt gebruiken omdat je snel een bepaald probleem op wilt lossen en je even een weggooiscriptje schrijft: prima. Helemaal begrijpelijk. Maar de TS wil graag goed OO leren, begrijp ik uit het topic, en dan past gegoochel met magic getters en setters er gewoon niet, omdat het bepaald geen goed design is.

Edit: en TS, je hoeft dat framework nu nog niet te gebruiken. Je merkt vanzelf welke dingen je steeds weer tegenkomt en die eigenlijk heel repetitief voelen - dat zijn de dingen die het framework over gaat nemen. Maar dat hoeft nu nog niet. En blijf ook vooral nog even query's schrijven, want ook dat is erg leerzaam. En daar blijf je mee te maken houden, want ook met ORM heb je met regelmaat toch uitgeschreven query's nodig.

[ Voor 15% gewijzigd door incaz op 08-11-2016 09:20 ]

Never explain with stupidity where malice is a better explanation


Acties:
  • 0 Henk 'm!

  • HollowGamer
  • Registratie: Februari 2009
  • Niet online
Waarom zie je magic methods niet als OOP/bad practice (design)? Het is juist gemaakt voor OOP.
http://php.net/manual/en/language.oop5.magic.php
Vind je __toString() dan ook een foute method, en schrijf je dit liever zelf? Wat bedoel je precies?

Is het echt belangrijk die auto hint bij IDE's? Ik neem toch aan dat je weet welke key je aanroept en niet gaat 'gokken'? Met logische namen heb ik deze hints nooit nodig gehad. PHP geeft wel degelijk een melding bij niet bestaande keys, en dat is toch niet erg? :?

[ Voor 17% gewijzigd door HollowGamer op 08-11-2016 12:56 ]


Acties:
  • +1 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
HollowGamer schreef op dinsdag 08 november 2016 @ 12:54:
[...]

Waarom zie je magic methods niet als OOP/bad practice (design)? Het is juist gemaakt voor OOP.
http://php.net/manual/en/language.oop5.magic.php
Vind je __toString() dan ook een foute method, en schrijf je dit liever zelf? Wat bedoel je precies?

Is het echt belangrijk die auto hint bij IDE's? Ik neem toch aan dat je weet welke key je aanroept en niet gaat 'gokken'? Met logische namen heb ik deze hints nooit nodig gehad. PHP geeft wel degelijk een melding bij niet bestaande keys, en dat is toch niet erg? :?
Nodig is het niet natuurlijk, maar wel handig. Al kan je ook gewoon phpdocs toevoegen aan je class om aan te geven welke properties/classes je met magic getters kan aanroepen.

Ik vind het persoonlijk altijd wel prettig als dat aangevuld wordt, natuurlijk zijn de meeste dingen logisch, maar om typfouten te voorkomen is aanvullen of een waarschuwing als hij niet bestaat gewoon makkelijk.


Wel goed om te leren hoe je met 'plat php' en PDO queries maakt en schrijft, maar sinds ik Laravel gebruik met Eloquent, zou ik echt niet meer terug willen :P Allicht kan je zelf JOINS schrijven, maar gewoon relaties in je model zetten en een nette API is wel een stuk makkelijker..

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb zelf een nieuw bestand gemaakt en opnieuw een stukje code geschreven.
Dit na alle reacties te hebben gelezen. Tijdens het schrijven van de code niet op Tweakers gekeken om het even echt geheel zelf te proberen.

Het volgende komt eruit en het werkt.
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
<?php
class Student{
    public $voornaam;
    public $studentnummer;
}
class Student_Repository{
    private $_db;
    
    public function __construct($db){
        $this->_db = $db;
    }
    
    public function getAllStudents(){
        try{
            $result = $this->_db->prepare("SELECT * FROM student");
            $result->execute();
            
            $mapper = new Record_To_Student();
            
            $outputList = array();
            
            while($record = $result->fetch()){
                $student = new Student();
                
                $mapper->mapper($record, $student);
                
                $outputList[] = $student;
            }
            
            return $outputList;
        }
        catch(PDOException $err){
            return false;
        }
    }
}
class Record_To_Student{
    public function mapper($record, $student){
        $student->voornaam = $record['voornaam'];
        $student->studentnummer = $record['studentnummer'];
    }
}

try{
    $pdo = new PDO('mysql:host=localhost;dbname=student;port=port', 'user', 'pass');
    $student = new Student_Repository($pdo);
    
    $students = $student->getAllStudents();
    
    if(!$students){
        echo 'Er is een fout opgetreden!';
    }
    else{
        print_r($students);
    }
}
catch(PDOException $err){
    echo 'Er is iets fout gegaan!';
}


Ik hoor graag wat jullie er van vinden.

Wat is nou eigenlijk het daadwerkelijke doel van een mapper? Ik heb het hier gebruikt, maar ik zou toch ook een array van de resultaten uit de query kunnen maken en die direct returnen?

Ik hoor het graag :)

[ Voor 2% gewijzigd door Verwijderd op 08-11-2016 19:07 . Reden: Correctie ]


Acties:
  • 0 Henk 'm!

Verwijderd

Verwijderd schreef op dinsdag 08 november 2016 @ 19:02:
Wat is nou eigenlijk het daadwerkelijke doel van een mapper?
In dit geval? Geen idee... ;)

Acties:
  • 0 Henk 'm!

  • douchekip
  • Registratie: Oktober 2016
  • Laatst online: 04-01-2023
Het nut van een "Mapper" is om platte data (in dit geval uit de database) om te zetten naar een in-memory representatie waar het programma mee kan werken (in dit geval een Student object), en vice versa.

In het voorbeeld is de data structuur 1:1 gelijk aan de velden van de Student class, dus is de losse Record_To_Student mapper een beetje overkill.


Een iets versimpelde uitleg:
Mappers zijn om data heen en weer te converteren.
Repositories zijn queries te bouwen.


In jouw voorbeeld heb je eigenlijk al iets te veel 'converteer' code in je repository.

[ Voor 24% gewijzigd door douchekip op 08-11-2016 20:24 ]


Acties:
  • 0 Henk 'm!

  • incaz
  • Registratie: Augustus 2012
  • Laatst online: 15-11-2022
Het doel van een de map-functie is het omzetten van een array (dat je terugkrijgt van de db) naar een object (de student.)

Het doel van OO is dat je de objecten gebruikt om verder mee te werken. Over een tijdje wil je het programma bv uitbreiden en schrijf je een functie die aan een Student een Opdracht mee kan geven. Dat is veel duidelijker dan als je zegt 'aan een array een array meegeven.' Als je weet dat iets een Student is, weet je bv dat je te maken hebt met studentnummers en voornamen. Als je weet dat iets een Opdracht is, kun je dingen verwachten als 'titel' en 'sluitdatum' - maar geen voornaam.

Objecten zijn dus om dat gebruik helder te maken.

Dan je repository: dat is een object dat communiceert met de database en je een verzameling studenten (of een losse student) teruggeeft.
Dat is niet hetzelfde als een Student zelf, de repository zelf heeft geen studentnummer of voornaam, en gaat geen Opdrachten inleveren. In dit geval is het gebruik van de variabelenaam $student voor een repository-object dus wat verwarrend.

In dit geval zou ik dus denken dat het laatste deel van de code logischer is met een naamgeving als volgt:
PHP:
1
2
3
4
5
6
7
8
$student_repo = new Student_Repository($pdo);
    
$students = $student_repo->getAllStudents();

// en dan iets als 
foreach( $students as $student){
   // hier kun je dan iets met elke $student doen. 
}


Tot slot kun je de mapper-functie opnemen in de repository-class. Dat hoort ook allemaal qua functionaliteit bij elkaar: het gaat om de verbinding tussen de database en je object.

Never explain with stupidity where malice is a better explanation


Acties:
  • 0 Henk 'm!

  • HollowGamer
  • Registratie: Februari 2009
  • Niet online
Vind het allemaal wat ver gaan, begin gewoon bij het begin van OOP.
Het leren van de magic_methods autoloading, extends, interface, etc. lijkt mij veel beter.

Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
Je kunt natuurlijk ook te ver doorschieten met OOP. Wat het belangrijkste is, is dat je goed gebruikt maakt van de functionaliteit van de gebruikte programmeertaal. Veel design-patterns en andere OOP constructies zijn voor oorspronkelijk bedoeld voor Java, omdat er in Java vaak geen andere manier is om het correct te doen. In PHP gelden andere OOP regels, die niet in lijn zijn met die van bijvoorbeeld Java, maar daardoor niet fout.

Acties:
  • +1 Henk 'm!

  • incaz
  • Registratie: Augustus 2012
  • Laatst online: 15-11-2022
HollowGamer schreef op dinsdag 08 november 2016 @ 21:12:
[...]

Vind het allemaal wat ver gaan, begin gewoon bij het begin van OOP.
Het leren van de magic_methods autoloading, extends, interface, etc. lijkt mij veel beter.
Het begin van OOP? Brr, nee hoor. Het begin van OOP is dat het gaat om objecten.
Magic_methods en autoloading zijn vooral handigheidjes (en neem daar vooral een framework voor, dan krijg je namelijk nog heel veel andere handigheidjes er gratis en voor niets bij) maar hebben niets met de basis van OOP te maken.
Extends en interface zijn wel fundamenteel als je wat feeling krijgt wat een object uberhaupt is, maar voorlopig nog niet. En dat is ook niet de core van OOP.

Never explain with stupidity where malice is a better explanation


Acties:
  • +2 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
Verwijderd schreef op dinsdag 08 november 2016 @ 19:02:

Wat is nou eigenlijk het daadwerkelijke doel van een mapper? Ik heb het hier gebruikt, maar ik zou toch ook een array van de resultaten uit de query kunnen maken en die direct returnen?

Ik hoor het graag :)
Je kan ook gewoon PDO je resultaat direct laten mappen naar je class:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class StudentRepository
{
    /** @var PDO $_db */
    private $_db;

    public function __construct(PDO $db) 
    {
        $this->_db = $db;
    }

    public function getAllStudents()
    {
        $result = $this->_db->prepare("SELECT * FROM student");
        $result->setFetchMode(PDO::FETCH_CLASS, Student::class);
        $result->execute();

        return $result->fetchAll();
    }
}

Dan heb je die Record_To_Student class + die foreach loop helemaal niet nodig.
Leer je overigens ook meteen aan je constructor argumenten te typehinten, zodat het duidelijk is wat je verwacht. Tevens kan je IDE je dan nuttige meldingen geven.

En natuurlijk zou je, om OOP te oefenen, een BaseRepository kunnen maken, die bijvoorbeeld de DB constructor + ophalen van resultaten (1 of meerdere) doet, terwijl je dan in je StudentRepository alleen bijv. '$this->fetchRows("SELECT * FROM student")' hoeft te doen.

Edit: zoiets dus:

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
abstract class BaseRepository
{
    private $_db;
    protected $classname;

    public function __construct(PDO $db)
    {
        $this->_db = $db;
    }

    public function fetch($query, $parameters = [])
    {
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);

        return $result->fetch();
    }

    public function fetchAll($query, $parameters = [])
    {
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);

        return $result->fetchAll();
    }
}

class StudentRepository extends BaseRepository
{
    protected $classname = Student::class;

    /**
     * @return array|Student[]
     */
    public function getAllStudents()
    {
        return $this->fetchAll("SELECT * FROM student");
    }

    /**
     * @param int $nummer
     * @return Student
     */
    public function getStudent($nummer)
    {
        return $this->fetch("SELECT * FROM student WHERE `studentnummer` = :nummer LIMIT 0,1", [':nummer' => $nummer]);
    }
}

(Al kan je misschien beter je values expliciet binden met bindParam om het goede type te krijgen)

En als je dan echt pietje precies wil zijn, ga dan meteen voor PSR-1 + PSR-2 styling, dus StudentRepository ipv Student_Repository, en andere braces etc.

[ Voor 28% gewijzigd door Barryvdh op 08-11-2016 23:59 ]


Acties:
  • +1 Henk 'm!

  • Bee.nl
  • Registratie: November 2002
  • Niet online

Bee.nl

zoemt

Magic methods moet je niet te scheutig mee zijn. Het maakt het debuggen en opsporen van usages lastiger. Er zijn uiteraard handige use cases voor, maar by default kun je properties en methods het best expliciet definiëren. Een goede IDE (PhpStorm) kan deze automatisch voor je genereren.
ThomasG schreef op dinsdag 08 november 2016 @ 21:19:
Je kunt natuurlijk ook te ver doorschieten met OOP. Wat het belangrijkste is, is dat je goed gebruikt maakt van de functionaliteit van de gebruikte programmeertaal. Veel design-patterns en andere OOP constructies zijn voor oorspronkelijk bedoeld voor Java, omdat er in Java vaak geen andere manier is om het correct te doen. In PHP gelden andere OOP regels, die niet in lijn zijn met die van bijvoorbeeld Java, maar daardoor niet fout.
Niet mee eens. Design patterns zijn niet gebonden aan een taal. Het zijn blauwdrukken van bepaalde gedragingen/constructies die ingezet kunnen worden tot het oplossen/huisvesten van bepaalde probleemstukken. Iedere taal heeft zo zijn eigen implementatiedetails op het gebied van OOP, maar in grote lijnen blijft het gedachtegoed hetzelfde.

Acties:
  • +2 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
Bee.nl schreef op dinsdag 08 november 2016 @ 21:29:
[...]

Magic methods moet je niet te scheutig mee zijn. Het maakt het debuggen en opsporen van usages lastiger. Er zijn uiteraard handige use cases voor, maar by default kun je properties en methods het best expliciet definiëren. Een goede IDE (PhpStorm) kan deze automatisch voor je genereren.
[...]

Niet mee eens. Design patterns zijn niet gebonden aan een taal. Het zijn blauwdrukken van bepaalde gedragingen/constructies die ingezet kunnen worden tot het oplossen/huisvesten van bepaalde probleemstukken. Iedere taal heeft zo zijn eigen implementatiedetails op het gebied van OOP, maar in grote lijnen blijft het gedachtegoed hetzelfde.
Design patterns zijn niet perse gebonden aan een taal. Maar als je zoekt naar design patterns zijn de meeste ontworpen voor Java. Als je die zonder na te denken copy-paste in PHP, dan doe je gewoon iets niet goed. Want veel van de Gang of Four design patterns heb je óf niet nodig in PHP, óf kun je op een andere - in die taal efficiëntere - manier doen. Het wordt daardoor niet ineens minder OOP, enkel op een andere manier.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
HollowGamer schreef op dinsdag 08 november 2016 @ 21:12:
[...]

Vind het allemaal wat ver gaan, begin gewoon bij het begin van OOP.
Het leren van de magic_methods autoloading, extends, interface, etc. lijkt mij veel beter.
Ik ben al een weekje bezig met OOP.
Ik heb diverse tutorials gevolgd waarin de magic_methods, extends en interface terugkwamen ;).

Ik wil me nu alleen (misschien te snel) verdiepen in OOP en databases.

Acties:
  • +2 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
Verwijderd schreef op dinsdag 08 november 2016 @ 21:45:
[...]


Ik ben al een weekje bezig met OOP.
Ik heb diverse tutorials gevolgd waarin de magic_methods, extends en interface terugkwamen ;).

Ik wil me nu alleen (misschien te snel) verdiepen in OOP en databases.
Vergeet vooral ook niet PHP The Right Way even door te kijken (is volgens mij nog niet langs gekomen)

http://www.phptherightway.com/

Staat ook een (beknopt) stuk over Databases, Dependency Injection, Design Patterns en natuurlijk Security.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Barryvdh schreef op dinsdag 08 november 2016 @ 21:27:
[...]


Je kan ook gewoon PDO je resultaat direct laten mappen naar je class:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class StudentRepository
{
    /** @var PDO $_db */
    private $_db;

    public function __construct(PDO $db) 
    {
        $this->_db = $db;
    }

    public function getAllStudents()
    {
        $result = $this->_db->prepare("SELECT * FROM student");
        $result->setFetchMode(PDO::FETCH_CLASS, Student::class);
        $result->execute();

        return $result->fetchAll();
    }
}

Dan heb je die Record_To_Student class + die foreach loop helemaal niet nodig.
Leer je overigens ook meteen aan je constructor argumenten te typehinten, zodat het duidelijk is wat je verwacht. Tevens kan je IDE je dan nuttige meldingen geven.

En natuurlijk zou je, om OOP te oefenen, een BaseRepository kunnen maken, die bijvoorbeeld de DB constructor + ophalen van resultaten (1 of meerdere) doet, terwijl je dan in je StudentRepository alleen bijv. '$this->fetchRows("SELECT * FROM student")' hoeft te doen.

Edit: zoiets dus:

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
abstract class BaseRepository
{
    private $_db;
    protected $classname;

    public function __construct(PDO $db)
    {
        $this->_db = $db;
    }

    public function fetch($query, $parameters = [])
    {
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);

        return $result->fetch();
    }

    public function fetchAll($query, $parameters = [])
    {
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);

        return $result->fetchAll();
    }
}

class StudentRepository extends BaseRepository
{
    protected $classname = Student::class;

    /**
     * @return array|Student[]
     */
    public function getAllStudents()
    {
        return $this->fetchAll("SELECT * FROM student");
    }

    /**
     * @param $id
     * @return Student
     */
    public function getStudent($id)
    {
        return $this->fetch("SELECT * FROM student WHERE `id` = :id LIMIT 0,1", [':id' => $id]);
    }
}

(Al kan je misschien beter je values expliciet binden met bindParam om het goede type te krijgen)

En als je dan echt pietje precies wil zijn, ga dan meteen voor PSR-1 + PSR-2 styling, dus StudentRepository ipv Student_Repository, en andere braces etc.
Super bedankt! :) Ik ga er even mee knutselen!
Barryvdh schreef op dinsdag 08 november 2016 @ 21:50:
[...]

Vergeet vooral ook niet PHP The Right Way even door te kijken (is volgens mij nog niet langs gekomen)

http://www.phptherightway.com/

Staat ook een (beknopt) stuk over Databases, Dependency Injection, Design Patterns en natuurlijk Security.
Bedankt voor de link, deze was inderdaad nog niet genoemd!

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Goed, ik ben even bezig geweest.
Ik heb er voor gekozen om terug terug te gaan naar MYSQLI, hiermee heb ik op dit moment de meeste ervaring dus wil ik eerst daarmee oefenen.

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
<?php
class Student 
{
    public $voornaam;
    public $studentnummer;
}


abstract class BaseRepository
{
    protected $_db;
    protected $_classname;
    
    public function __construct(MYSQLI $db)
    {
        $this->_db = $db;
    }
    
    public function fetchAll($query){
        $result = $this->_db->query($query);
        $result->fetch_object($this->_classname);
        return $result->fetch_all();
    }   
}

class StudentRepository extends BaseRepository
{
    protected $_classname = 'Student';
    
    public function getAllStudents()
    {
        return $this->fetchAll("SELECT * FROM student");
    }
    
    public function getStudent($studentnummer){
        if(is_int($studentnummer)){
            $studentnummer = $this->_db->real_escape_string($studentnummer);
        
            return $this->fetchAll("SELECT * FROM student WHERE studentnummer='".$studentnummer."'");
        } else{
            echo 'Studentnummer moet een getal zijn!';
        }
    }
}

$mysqli = new mysqli("localhost", "user", "pass", "student");

if(mysqli_connect_errno()){
    echo 'Er is een fout opgetreden!';
} else{
    $studentRepository = new StudentRepository($mysqli);
    $student = $studentRepository->getStudent(1000200);
    print_r($student);
}


Als ik bij 'getStudent' zeg dat het studentnummer gelijk moet zijn aan het opgegeven studentnummer krijg ik als output: Array(). Als ik zeg dat deze ongelijk moet zijn aan het opgegeven studentnummer krijg ik wel een output.
Hoe kan dat?

Acties:
  • +2 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
Verwijderd schreef op dinsdag 08 november 2016 @ 23:10:
Goed, ik ben even bezig geweest.
Ik heb er voor gekozen om terug terug te gaan naar MYSQLI, hiermee heb ik op dit moment de meeste ervaring dus wil ik eerst daarmee oefenen.

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
<?php
class Student 
{
    public $voornaam;
    public $studentnummer;
}


abstract class BaseRepository
{
    protected $_db;
    protected $_classname;
    
    public function __construct(MYSQLI $db)
    {
        $this->_db = $db;
    }
    
    public function fetchAll($query){
        $result = $this->_db->query($query);
        $result->fetch_object($this->_classname);
        return $result->fetch_all();
    }   
}

class StudentRepository extends BaseRepository
{
    protected $_classname = 'Student';
    
    public function getAllStudents()
    {
        return $this->fetchAll("SELECT * FROM student");
    }
    
    public function getStudent($studentnummer){
        if(is_int($studentnummer)){
            $studentnummer = $this->_db->real_escape_string($studentnummer);
        
            return $this->fetchAll("SELECT * FROM student WHERE studentnummer='".$studentnummer."'");
        } else{
            echo 'Studentnummer moet een getal zijn!';
        }
    }
}

$mysqli = new mysqli("localhost", "user", "pass", "student");

if(mysqli_connect_errno()){
    echo 'Er is een fout opgetreden!';
} else{
    $studentRepository = new StudentRepository($mysqli);
    $student = $studentRepository->getStudent(1000200);
    print_r($student);
}


Als ik bij 'getStudent' zeg dat het studentnummer gelijk moet zijn aan het opgegeven studentnummer krijg ik als output: Array(). Als ik zeg dat deze ongelijk moet zijn aan het opgegeven studentnummer krijg ik wel een output.
Hoe kan dat?
Omdat je het resultaat al ophaalt met '$result->fetch_object($this->_classname);' maar er verder niks mee doet. Daarna roep je nogmaals een fetch aan, maar heb je alle resultaten al opgehaald.

Maar doe dit nou niet. Vergeet mysqli, gebruik gewoon PDO met prepared statements. Of in het uiterste geval mysqli maar dan wel met Prepared statements. Eenmaal aangeleerd is moeilijk af te leren.

(En stop dan ook meteen met properties prefixen met een underscore, mag ook niet volgens PSR-2)
Property names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility.
Dat is een overblijfsel van toen er nog geen protected/private keywords waren..

Acties:
  • +1 Henk 'm!

  • mrBako
  • Registratie: November 2011
  • Laatst online: 18:59
Offtopic:
Hoewel ik weinig ervaring heb met php zie ik iets verdachts aan de queries die je opbouwt.
Leer jezelf aan om met parameters te werken en niet via if statements waarin geparsed wordt.
Zo verklein(lees voorkom) je SQL injections.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Barryvdh schreef op woensdag 09 november 2016 @ 00:08:
[...]


Omdat je het resultaat al ophaalt met '$result->fetch_object($this->_classname);' maar er verder niks mee doet. Daarna roep je nogmaals een fetch aan, maar heb je alle resultaten al opgehaald.

Maar doe dit nou niet. Vergeet mysqli, gebruik gewoon PDO met prepared statements. Of in het uiterste geval mysqli maar dan wel met Prepared statements. Eenmaal aangeleerd is moeilijk af te leren.

(En stop dan ook meteen met properties prefixen met een underscore, mag ook niet volgens PSR-2)

[...]

Dat is een overblijfsel van toen er nog geen protected/private keywords waren..
Oké, bedankt. Ik zal later vandaag het aanpassen en mijn nieuwe code posten!

Acties:
  • +1 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Goed, ik heb nu deze code weer:
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
<?php
class Student
{
    public $voornaam;
    public $studentnummer;
}
abstract class BaseRepository
{
    private $_db;
    protected $classname;
    
    public function __construct(PDO $db){
        $this->_db = $db;
    }
    
    public function fetch($query, $parameters = []){
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);
        
        return $result->fetch();
    }
    public function fetchAll($query, $parameters = []){
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);
        
        return $result->fetchAll();
    }
}
class StudentRepository extends BaseRepository
{
    protected $classname = 'student';
    
    public function getAllStudents()
    {
        return $this->fetchAll("SELECT studentnummer, voornaam FROM student");
    }
    
    public function getStudent($studentnummer)
    {
        return $this->fetch("SELECT * FROM student WHERE studentnummer = :nummer LIMIT 0,1", [':nummer' => $studentnummer]);
    }
}

try{
    $pdo = new PDO('mysql:host=localhost;dbname=student;port=port', 'user', 'pass');
    $student = new StudentRepository($pdo);
    
    $student1 = $student->getStudent('S1001902');
    
    if(!$student1){
        echo 'Er is een fout opgetreden bij het ophalen van de student!';
    }
    else{
        print_r($student1);
    }
}
catch(PDOException $err){
    echo 'Er is iets fout gegaan!'.$err;
}


Als ik het goed begrijp kan ik dus nu de voornaam van deze student als volgt weergeven:
PHP:
1
echo $student1->voornaam;

Het verschil is dus dat je nu een object terug krijgt als data ipv een array (bv)?

En:
PHP:
1
2
3
4
5
$students = $student->getAllStudents();

foreach($students as $student){
    echo $students->voornaam.'<br>';
}

[ Voor 5% gewijzigd door Verwijderd op 09-11-2016 19:29 ]


Acties:
  • +1 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
Verwijderd schreef op woensdag 09 november 2016 @ 19:26:

Als ik het goed begrijp kan ik dus nu de voornaam van deze student als volgt weergeven:
PHP:
1
echo $student1->voornaam;

Het verschil is dus dat je nu een object terug krijgt als data ipv een array (bv)?

En:
PHP:
1
2
3
4
5
$students = $student->getAllStudents();

foreach($students as $student){
    echo $students->voornaam.'<br>';
}
Bijvoorbeeld ja, maar nu je een object hebt kan je daar ook meer mee. In huidige vorm is het niet zo spannend, maar je zou bijvoorbeeld aan zoiets kunnen denken:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Student
{
    public $voornaam;
    public $achternaam;
    public $studentnummer;

    public function getFullName()
    {
        return $this->voornaam . ' ' . $this->achternaam;
    }

    public function hasValidNumber()
    {
        return substr($this->studentnummer, 0, 1) == 'S';
    }
}


Dan is je Student dus je 'Model' dat data bevat maar ook bepaalde methodes om iets nuttigs te doen met de data (in plaats van dat in je templates/weergave code te doen.

En omdat je met objecten werkt, kan je ook wederom typehints gebruiken, zodat je zeker weet dat je een bepaald object hebt.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class School
{
    protected $students = [];

    public function addStudent(Student $student)
    {
        $this->students[] = $student;
    }
}

$student1 = $student->getStudent('S1001902');
    
$school = new School();
$school->addStudent($student1);

Dat zou dus een fout geven als je er een andere class in probeert te stoppen.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Barryvdh schreef op woensdag 09 november 2016 @ 20:08:
[...]


Bijvoorbeeld ja, maar nu je een object hebt kan je daar ook meer mee. In huidige vorm is het niet zo spannend, maar je zou bijvoorbeeld aan zoiets kunnen denken:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Student
{
    public $voornaam;
    public $achternaam;
    public $studentnummer;

    public function getFullName()
    {
        return $this->voornaam . ' ' . $this->achternaam;
    }

    public function hasValidNumber()
    {
        return substr($this->studentnummer, 0, 1) == 'S';
    }
}


Dan is je Student dus je 'Model' dat data bevat maar ook bepaalde methodes om iets nuttigs te doen met de data (in plaats van dat in je templates/weergave code te doen.

En omdat je met objecten werkt, kan je ook wederom typehints gebruiken, zodat je zeker weet dat je een bepaald object hebt.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class School
{
    protected $students = [];

    public function addStudent(Student $student)
    {
        $this->students[] = $student;
    }
}

$student1 = $student->getStudent('S1001902');
    
$school = new School();
$school->addStudent($student1);

Dat zou dus een fout geven als je er een andere class in probeert te stoppen.
Bedankt! Ik begrijp nu ook waarom het handig is om de resultaten om te zetten naar een object! :)

Maar de classes, maak je hiervoor per class een apart PHP bestand aan die je vervolgens include/require? Of maak je een algmeen bestand met alle classes die je include/require?

En de naam student in het onderstaand voorbeeld is eigenlijk niet juist voor deze variabele, zoals iemand al eerder aangaf in dit topic. Zal studentRepository een goede naam zijn?
PHP:
1
2
$student = new studentRepository($pdo);
$students = $student->getAllStudents();

Acties:
  • +1 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
Verwijderd schreef op woensdag 09 november 2016 @ 22:42:
[...]


Bedankt! Ik begrijp nu ook waarom het handig is om de resultaten om te zetten naar een object! :)

Maar de classes, maak je hiervoor per class een apart PHP bestand aan die je vervolgens include/require? Of maak je een algmeen bestand met alle classes die je include/require?

En de naam student in het onderstaand voorbeeld is eigenlijk niet juist voor deze variabele, zoals iemand al eerder aangaf in dit topic. Zal studentRepository een goede naam zijn?
PHP:
1
2
$student = new studentRepository($pdo);
$students = $student->getAllStudents();
Conventie is om per class 1 bestand aan te maken. In PHP kan je dan een zogenaamde autoload gebruiken die alle classes voor je laadt, zoals PSR-4.
Je hebt in PHP ook namespaces, dus dan krijg je grofweg zoiets:

Namespace App -> mapje src/
class App\Models\Student -> src/Models/Student.php
class App\Repositories\StudentRepository -> src/Repositories/StudentRepository.php

in je index.php laad je dan de autoloader, daarna kan je gewoon new App\Models\Student() doen. Makkelijkste is om dit met Composer te doen, omdat je dat waarschijnlijk toch wil gebruiken later; https://getcomposer.org/
Zie bijvoorbeeld https://laracasts.com/lessons/psr-4-autoloading

Maar als dat wat te complex voor nu is, kan je ook gewoon je autoloader registreren: http://php.net/manual/en/function.spl-autoload-register.php
PHP:
1
2
3
spl_autoload_register(function ($class) {
    include 'src/' . $class . '.php';
});


Elke keer als je dan een class probeert aan te maken/gebruiken, zoek hij in src/<class naam>.php naar het bestand.

En ja, je naam is niet zo handig, beter zoiets:
PHP:
1
2
3
$studentRepository = new StudentRepository($pdo);
$students = $studentRepository->getAllStudents();
$student = $studentRepository->getStudent('S0123');


Of als je minder dubbelop wil doen:

PHP:
1
2
3
$studentRepository = new StudentRepository($pdo);
$students = $studentRepository->all();
$student = $studentRepository->findNumber('S0123');

[ Voor 4% gewijzigd door Barryvdh op 10-11-2016 10:02 ]


Verwijderd

Topicstarter
Barryvdh schreef op donderdag 10 november 2016 @ 10:01:
[...]


Conventie is om per class 1 bestand aan te maken. In PHP kan je dan een zogenaamde autoload gebruiken die alle classes voor je laadt, zoals PSR-4.
Je hebt in PHP ook namespaces, dus dan krijg je grofweg zoiets:

Namespace App -> mapje src/
class App\Models\Student -> src/Models/Student.php
class App\Repositories\StudentRepository -> src/Repositories/StudentRepository.php

in je index.php laad je dan de autoloader, daarna kan je gewoon new App\Models\Student() doen. Makkelijkste is om dit met Composer te doen, omdat je dat waarschijnlijk toch wil gebruiken later; https://getcomposer.org/
Zie bijvoorbeeld https://laracasts.com/lessons/psr-4-autoloading

Maar als dat wat te complex voor nu is, kan je ook gewoon je autoloader registreren: http://php.net/manual/en/function.spl-autoload-register.php
PHP:
1
2
3
spl_autoload_register(function ($class) {
    include 'src/' . $class . '.php';
});


Elke keer als je dan een class probeert aan te maken/gebruiken, zoek hij in src/<class naam>.php naar het bestand.

En ja, je naam is niet zo handig, beter zoiets:
PHP:
1
2
3
$studentRepository = new StudentRepository($pdo);
$students = $studentRepository->getAllStudents();
$student = $studentRepository->getStudent('S0123');


Of als je minder dubbelop wil doen:

PHP:
1
2
3
$studentRepository = new StudentRepository($pdo);
$students = $studentRepository->all();
$student = $studentRepository->findNumber('S0123');
Bedankt!
Ik ga nu zelf proberen om een heel eenvoudig beheersysteem voor een website te maken, object georiënteerd te maken! (voorkant, en achterkant: pagina maken, aanpassen, verwijderen)
Niet object georiënteerd heb ik dit al vaak gedaan ;)

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Dan raad ik als nog aan om naar bestaande frameworks te kijken, want je maakt nu allemaal spul waar fouten in kunnen sluipen. Bijvoorbeeld niet parametizen van queries, en bij bestaand spul heb je al een goede basis, zodat je sneller resultaten kunt boeken. Anders ben je een jaar verder heb je een half framework en geen product.

Acties:
  • +2 Henk 'm!

  • Tjolk
  • Registratie: Juni 2007
  • Laatst online: 22:09
4Real schreef op donderdag 10 november 2016 @ 16:53:
Dan raad ik als nog aan om naar bestaande frameworks te kijken, want je maakt nu allemaal spul waar fouten in kunnen sluipen. Bijvoorbeeld niet parametizen van queries, en bij bestaand spul heb je al een goede basis, zodat je sneller resultaten kunt boeken. Anders ben je een jaar verder heb je een half framework en geen product.
Allemaal leuk en aardig natuurlijk, maar volgens mij gaat het -NR- niet om het product. Hij wil snappen wat er gebeurd en WAAROM. En dan is dit een prima methode om jezelf wat wijzer te maken.

Anders kan-ie niet zo goed gewoon Wordpress installeren natuurlijk.

Tjolk is lekker. overal en altijd.


Verwijderd

Topicstarter
4Real schreef op donderdag 10 november 2016 @ 16:53:
Dan raad ik als nog aan om naar bestaande frameworks te kijken, want je maakt nu allemaal spul waar fouten in kunnen sluipen. Bijvoorbeeld niet parametizen van queries, en bij bestaand spul heb je al een goede basis, zodat je sneller resultaten kunt boeken. Anders ben je een jaar verder heb je een half framework en geen product.
Het parametizen van een query heb ik niet in deze code toegepast inderdaad, maar normaal doe ik dat natuurlijk wel.
Verder heb ik het over een zeer simpel systeem, het is niet uitgebreid met een enorme database, we spreken over een systeem van maximaal 5 tabellen. ;)

Verwijderd

Topicstarter
Goed, ik heb het projectje gewijzigd naar een webshopje (simpele).

Ik heb hieronder een klein stukje code, ik hoor graag jullie mening :)
En hoe zou je nu rowCount(); kunnen doen? :?

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php
class Product
{
    public $productName;
    public $productDescription;
    public $unitPrice;
    public $discount;
    
    public function getProductName()
    {
        return htmlspecialchars($this->productName);
    }
    public function getPriceWithDiscount()
    {
        return $this->unitPrice - ($this->discount / 100);
    }
}

abstract class BaseRepository
{
    private $_db;
    protected $classname;
    
    public function __construct(PDO $db)
    {
        $this->_db = $db;
    }
    
    public function fetch($query, $parameters = []){
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);
        
        return $result->fetch();
    }
    public function fetchAll($query, $parameters = []){
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);
        
        return $result->fetchAll();
    }
}
class ProductRepository extends BaseRepository
{
    protected $classname = 'Product';
    
    public function getAllProducts()
    {
        return $this->fetchAll("SELECT productName, productDescription, unitPrice, discount FROM product");
    }
        public function getProductByID($id)
    {
        return $this->fetch("SELECT productName, productDescription, unitPrice, discount 
FROM product WHERE ID = :id", [':id' => $id]);
    }
}


try{
    $pdo = new PDO('mysql:host=localhost;dbname=webshop;port=port', 'user', 'pass');
    $productRepository = new ProductRepository($pdo);
    $products = $productRepository->getAllProducts();
    
    if(!$products){
        echo 'Er is een fout opgetreden bij het laden van de producten.';
    } 
    else{
        foreach($products as $product)
        {
            echo '<h1>'.$product->getProductName().'</h1><br>';
            echo $product->getPriceWithDiscount();
        }
        
    }

        $product = $productRepository->getProductByID(13);

    if(!$product){
               echo 'Product kon niet worden opgehaald!';
        } 

    unset($pdo);
}
catch(PDOException $err){
    echo 'Er is iets fout gegaan!'.$err;
}

[ Voor 8% gewijzigd door Verwijderd op 10-11-2016 18:37 ]


Acties:
  • +1 Henk 'm!

  • mrBako
  • Registratie: November 2011
  • Laatst online: 18:59
Verwijderd schreef op donderdag 10 november 2016 @ 17:44:
En hoe zou je nu rowCount(); kunnen doen? :?
Zoals al eerder aangegeven ben ik niet ervaren met php, maar ik neem aan dat als je de getAllProducts() method aanroept ergens een array/list vult?
Php zal zeker een size_of of een count functie bevatten.

Verwijderd

Topicstarter
mbakirci schreef op donderdag 10 november 2016 @ 23:51:
[...]


Zoals al eerder aangegeven ben ik niet ervaren met php, maar ik neem aan dat als je de getAllProducts() method aanroept ergens een array/list vult?
Php zal zeker een size_of of een count functie bevatten.
Dat klopt! Bedankt.
Ben alleen benieuwd hoe je de rowCount function van PDO nu het beste kan gebruiken. :)

Acties:
  • 0 Henk 'm!

  • HollowGamer
  • Registratie: Februari 2009
  • Niet online
Wat is precies fout met een array gebruiken? Snap het punt van IDE's, maar waarom zou het niet mogen? Zeker tegenwoordig waar er steeds meer data bij komt, en het niet altijd hoeft te zijn dat een object alles bevat. Een studentmummer hoeft bijvoorbeeld nog niet zijn toegekend (toegeven dat dit niet wenselijk is), we weten nog niet alles over een student, etc. Moet je dan voor elk veld dit weer toevoegen aan de repository? 'Vroeger' had je nog beeld, maar steeds vaker komt er data bij/vallen stukjes weg, en gaan we naar steeds meer 'flexibele data'. Wat doe je als je van meerdere API's toch data wilt opslaan?
Het is toch goed mogelijk om data op te slaan als bijvoorbeeld JSON (zie NoSQL) en dit van (flexibele) keys te voorzien?

Niet om betweterig over te komem, maar zou het graag willen weten. :)

[ Voor 14% gewijzigd door HollowGamer op 11-11-2016 00:29 ]


Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
HollowGamer schreef op vrijdag 11 november 2016 @ 00:26:
Wat is precies fout met een array gebruiken? Snap het punt van IDE's, maar waarom zou het niet mogen?
Mag best, maar we hebben het hier over 'Object oriented' en arrays zijn geen objecten ;)
Een array zegt niks over de inhoud, maar een Student object geeft aan dat hij normaal gesproken voldoet aan een aantal verwachtingen qua velden en methodes. Daarnaast kan je dus aan dit 'Model' (om in MVC termen te spreken), extra methods toevoegen om het gebruik van die data makkelijker te maken (zie reactie van mij hier boven ergens).
HollowGamer schreef op vrijdag 11 november 2016 @ 00:26:
Zeker tegenwoordig waar er steeds meer data bij komt, en het niet altijd hoeft te zijn dat een object alles bevat. Een studentmummer hoeft bijvoorbeeld nog niet zijn toegekend (toegeven dat dit niet wenselijk is), we weten nog niet alles over een student, etc. Moet je dan voor elk veld dit weer toevoegen aan de repository?
Dit maakt niet uit. Als die data als null in je database staat, of je neemt hem niet mee in je select, zal je in het geval van je Model ook 'null' krijgen. Bij een array krijg je, in het laatste geval, een undefined index in dit geval, terwijl je object in beide gevallen null is: https://3v4l.org/FeN9v

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Student 
{
    public $studentnummer;
    public $voornaam;
}

$student = new Student();
$student->voornaam = 'Barry';

$data = ['voornaam' => 'Barry'];

var_dump(isset($student->studentnummer));  // false
var_dump(isset($data['studentnummer'])); // false

var_dump($student->studentnummer); // null
var_dump($data['studentnummer']); // undefined index

Ik weet niet welk veld je dan aan de repository moet toevoegen? Je bedoeld als property aan je Student class? Dat hoeft niet perse, maar is wel zo netjes. Anders werkt het ook gewoon: https://3v4l.org/FLHuK

PHP:
1
2
3
4
5
6
7
8
9
10
class Student 
{
    public $studentnummer;
    public $voornaam;
}

$student = new Student();
$student->achternaam = 'vd. H';

var_dump($student->achternaam); // vd. H
HollowGamer schreef op vrijdag 11 november 2016 @ 00:26:
'Vroeger' had je nog beeld, maar steeds vaker komt er data bij/vallen stukjes weg, en gaan we naar steeds meer 'flexibele data'. Wat doe je als je van meerdere API's toch data wilt opslaan?
Het is toch goed mogelijk om data op te slaan als bijvoorbeeld JSON (zie NoSQL) en dit van (flexibele) keys te voorzien?
Ik weet niet precies wat voor 'beeld' we vroeger hadden, maar flexibele data is leuk, maar als je het wil verwerken zal je het toch moet mappen naar 'vaste' data. In dit geval wil je Student niet zien als ruwe data, maar als een representatie van een student. In dit (simpele) voorbeeld mappen we de database 1 op 1 naar het Student model, maar dit hoeft niet zo te zijn in grotere applicaties. Maar alsnog zul je een Model/value object willen maken waarvan je weet welke properties/methods het bevat. En met een class (of interface) kan je zorgen dat je dit 'contract' vast legt.

In dit voorbeeld zou je de data van een API natuurlijk gewoon kunnen mappen naar je Student class. Voor de verdere code maakt het dan niet uit of je data van een API, database of gegeneerd wordt. https://3v4l.org/HrP0O

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 Student 
{
    public $studentnummer;
    public $voornaam;
}

$apiResult = [
    'firstName' => 'Barry',
    'sid' => 'S123',
];

$map = [
    'firstName' => 'voornaam',
    'sid' => 'studentnummer',
];

$student = new Student;
foreach ($apiResult as $key => $value) {
    if (isset($map[$key])) {
        $student->{$map[$key]} = $value;
    }
}

print_r($student);

Acties:
  • 0 Henk 'm!

  • incaz
  • Registratie: Augustus 2012
  • Laatst online: 15-11-2022
HollowGamer schreef op vrijdag 11 november 2016 @ 00:26:
Zeker tegenwoordig waar er steeds meer data bij komt, en het niet altijd hoeft te zijn dat een object alles bevat. Een studentmummer hoeft bijvoorbeeld nog niet zijn toegekend (toegeven dat dit niet wenselijk is), we weten nog niet alles over een student, etc. Moet je dan voor elk veld dit weer toevoegen aan de repository?
Ik zou het gebruik altijd voorop stellen. In mijn ervaring gaat het gebruik meestal om vrij duidelijk omschreven dingen: de eigenschappen hebben betekenis. Die betekenis zou ik zo veel mogelijk expliciet vastleggen, om te voorkomen dat dat uit elkaar gaat lopen. Het gaat bijvoorbeeld helemaal mis als er termen als 'studentnummer' 'studentnr' en 'studentid' door elkaar gebruikt gaan worden.
Het gebruiken van een expliciete class-definitie maakt dat je binnen je applicatie weet dat het altijd $student->getId() is en nooit iets anders. Moet je dan op een of andere manier aansluiten op andere termen, dan hoef je dat maar op 1 plek vast te leggen, daar waar je de connectie maakt. Dus heeft Blackboard andere ideeen over de terminologie dan je eigen db? Prima, geen probleem - dat regel je in je mapping, op 1 enkele plek, en nergens anders dan daar hoef je er rekening mee te houden.

Tegelijkertijd snap ik wel wat je zegt: het kan prima dat diverse databronnen data aanbieden via hun API waar (nog) niets mee gebeurt. Die kun je dan inderdaad zolang zonder structuur opslaan. Zodra je er echter gebruik van gaat maken, en het dus betekenis krijgt binnen je applicatie, verdient het een heldere centrale eenduidige definitie, zodat als de API-aanbieder de naamgeving ooit gaat veranderen (en dat gaan ze doen, geheid), je geen runtime errors krijgt (of in stilte falende zaken die je helemaal niet opmerkt), en dat je niet op 30 plekken de keys moet aan gaan passen, maar je dat allemaal op 1 centrale plek hebt.

(Even los van OO, een andere kant hiervan is trouwens dat het wettelijk in principe niet is toegestaan is om persoonsgegevens op te slaan als je die niet gebruikt. Maar bij bv producteigenschappen is dat niet aan de orde en gaat het verhaal wel op.)

Never explain with stupidity where malice is a better explanation


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb mijn code nu uitgebreid met de mogelijkheid voor de admin om een product toe te voegen.
Nu kwam meteen een vraag in mij op: Is het gebruikelijk om voor het admin gedeelte en de voorkant dezelfde class bestanden te gebruiken, of om aparte te gebruiken voor beide gedeeltes? (lijkt mij i.i.g. beter apart)

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<?php
class Product
{
    public $productName;
    public $productDescription;
    public $unitPrice;
    public $discount;
    
    public function getProductName()
    {
        return htmlspecialchars($this->productName);
    }
    public function getPriceWithDiscount()
    {
        return $this->unitPrice - ($this->discount / 100);
    }
}

abstract class BaseRepository
{
    private $_db;
    protected $classname;
    
    public function __construct(PDO $db)
    {
        $this->_db = $db;
    }
    
    public function fetch($query, $parameters = []){
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);
        
        return $result->fetch();
    }
    public function fetchAll($query, $parameters = []){
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result->execute($parameters);
        
        return $result->fetchAll();
    }
    public function insert($query, $parameters = []){
        $result = $this->_db->prepare($query);
        $result->setFetchMode(PDO::FETCH_CLASS, $this->classname);
        $result = $result->execute($parameters);
        
        if($result){
            return true;
        }
        else{
            return false;
        }
    }
}
class ProductRepository extends BaseRepository
{
    protected $classname = 'Product';
    
    public function getAllProducts()
    {
        return $this->fetchAll("SELECT productName, productDescription, unitPrice, discount FROM product");
    }
    
    public function getAllProductByCategory($category)
    {
        return $this->fetchAll("    
                                    SELECT * 
                                    FROM product AS p
                                    INNER JOIN product_category AS pc ON p.ID=pc.product_ID
                                    WHERE pc.category_ID = :category
        ", [':category' => $category]);
    }
    
    public function getProductById($id)
    {
        return $this->fetch("SELECT productName, productDescription, unitPrice, discount FROM product WHERE ID = :id", [':id' => $id]);
    }
    
    public function newProduct($productName, $productDescription, $unitPrice, $discount)
    {
        if($unitPrice > 0 && $discount > 0){
            return $this->insert("INSERT INTO product (ID, productName, productDescription, unitPrice, discount)
            VALUES ('', :productName, :productDescription, :unitPrice, :discount)", 
            [':productName' => $productName, ':productDescription' => $productDescription, ':unitPrice' => $unitPrice, ':discount' => $discount]);
        }
        else{
            return false;
        }
    }
}


try{
    $pdo = new PDO('mysql:host=localhost;dbname=webshop;port=pass', 'user', 'pass');
    $productRepository = new ProductRepository($pdo);
    $newProduct = $productRepository->newProduct('test', 'test', 1, 1);
    // Deze waarden worden vervangen door $_POST, maar dat formulier is er nog niet

    if(!$newProduct){
        echo 'Product is niet toegevoegd!';
    }
    
    $products = $productRepository->getAllProducts();
    
    if($products){
        foreach($products as $product)
        {
            echo $product->productName;
        }
    }
    else{
        echo 'Producten konden niet owrden opgehaald!';
    }
    
    unset($pdo);
}
catch(PDOException $err){
    echo 'Er is iets fout gegaan!'.$err;
}

Acties:
  • 0 Henk 'm!

  • Bee.nl
  • Registratie: November 2002
  • Niet online

Bee.nl

zoemt

HollowGamer schreef op vrijdag 11 november 2016 @ 00:26:
Wat is precies fout met een array gebruiken? Snap het punt van IDE's, maar waarom zou het niet mogen? Zeker tegenwoordig waar er steeds meer data bij komt, en het niet altijd hoeft te zijn dat een object alles bevat. Een studentmummer hoeft bijvoorbeeld nog niet zijn toegekend (toegeven dat dit niet wenselijk is), we weten nog niet alles over een student, etc. Moet je dan voor elk veld dit weer toevoegen aan de repository? 'Vroeger' had je nog beeld, maar steeds vaker komt er data bij/vallen stukjes weg, en gaan we naar steeds meer 'flexibele data'. Wat doe je als je van meerdere API's toch data wilt opslaan?
Het is toch goed mogelijk om data op te slaan als bijvoorbeeld JSON (zie NoSQL) en dit van (flexibele) keys te voorzien?

Niet om betweterig over te komem, maar zou het graag willen weten. :)
Ter aanvulling op de prima uitleg van Barryvdh en incaz:

Dergelijke flexibiliteit en dynamische data (of 'magic' zoals ik het wel eens noem), werkt in het begin leuk en aardig. Echter, wanneer je applicatie groter begin te worden gaat dit steeds meer tegen je werken (kan ik uit ervaring vertellen). Je verliest grip op de properties, het tracken van usages wordt lastiger en het debuggen wordt steeds moeizamer.

Daarnaast is het met arrays de vraag of 1) de index bestaat en 2) wat de value type is. Met objecten heb je garantie dat de property/getter/setter bestaat en mbv phpdoc weet je meteen wat de argument/return types zijn. Dat helpt rare (cast) bugs en silent errors te voorkomen. Ergo, probeer altijd zo expliciet en strict mogelijk te programmeren, tenzij een edge case anders vereist.

Het is overigens geen probleem om je de data voor het einddoel (template, api, etc) te converteren naar een array, zolang je in de voorafgaande business logic maar werkt met de (OO) modellen.

Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
Bee.nl schreef op vrijdag 11 november 2016 @ 18:52:
[...]

Ter aanvulling op de prima uitleg van Barryvdh en incaz:

Dergelijke flexibiliteit en dynamische data (of 'magic' zoals ik het wel eens noem), werkt in het begin leuk en aardig. Echter, wanneer je applicatie groter begin te worden gaat dit steeds meer tegen je werken (kan ik uit ervaring vertellen). Je verliest grip op de properties, het tracken van usages wordt lastiger en het debuggen wordt steeds moeizamer.

Daarnaast is het met arrays de vraag of 1) de index bestaat en 2) wat de value type is. Met objecten heb je garantie dat de property/getter/setter bestaat en mbv phpdoc weet je meteen wat de argument/return types zijn. Dat helpt rare (cast) bugs en silent errors te voorkomen. Ergo, probeer altijd zo expliciet en strict mogelijk te programmeren, tenzij een edge case anders vereist.

Het is overigens geen probleem om je de data voor het einddoel (template, api, etc) te converteren naar een array, zolang je in de voorafgaande business logic maar werkt met de (OO) modellen.
Een beetje moderne PHP IDE kan anders prima met dynamische data omgaan. Steker nog, phpDoc bied daar functionaliteit voor.

Acties:
  • +1 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Verwijderd schreef op donderdag 10 november 2016 @ 23:53:
[...]


Dat klopt! Bedankt.
Ben alleen benieuwd hoe je de rowCount function van PDO nu het beste kan gebruiken. :)
Niet, je getAll functie geeft een array terug (of gooit een Exception). Maar met die array kun je verder werken. De count functie kun je gebruiken om te kijken of je uberhaupt resultaten hebt gekregen.
Verwijderd schreef op vrijdag 11 november 2016 @ 15:54:
Ik heb mijn code nu uitgebreid met de mogelijkheid voor de admin om een product toe te voegen.
Nu kwam meteen een vraag in mij op: Is het gebruikelijk om voor het admin gedeelte en de voorkant dezelfde class bestanden te gebruiken, of om aparte te gebruiken voor beide gedeeltes? (lijkt mij i.i.g. beter apart)
Je DataRepository heeft geen kennis van gebruikers of andere logica. Dit komt allemaal in je controller / business layer. Het enige wat de DataRepository doet is data uit de database omhalen, omzetten naar een entiteit class en teruggeven. Daarnaast kun je ook commando's (insert/update/delete) naar de database sturen. Tevens klinkt het als dat je dubbel werk gaat doen en dat is al en big no-no!

Daarnaast nog wat andere punten

Je product variabelen zijn public, maar je hebt ook weer een get wrapper voor één van de variabelen. Wees consitent, ga voor get/set wrappers (en verberg de variabelen middels protected of private), of houdt ze allemaal public.

[Je hebt veel getProductXXXXX als je in de product class zit of product repository zit dan is het al logisch wat je scope is. Product, dus het voegt niet meer toe. Doe gewoon hetvolgende:
PHP:
1
2
3
4
5
6
7
<?php

$product->getName();
$product->setName('naam van het product');

$productRepository->getByID();
$productRepository->getAll();


Zorg voor consitentie door in de BaseRepository abstract functies op te nemen voor handelingen welke sowieso gaan voorkomen.

PHP:
1
2
3
4
5
abstract class BaseRepository
{
    abstract public function getAll();
    abstract public function getByID();
}


En een functie geeft altijd één type terug. Ondanks dat het in PHP kan is het alvast netjes om aan te leren dat een functie één type of null terug geeft. Daarnaast kan hij altijd een Exception gooien.
Dus als je getByID functie null terug geeft dan heeft hij geen resultaat kunnen vinden. getAll kan een lege array teruggeven, dat is opzich een goede keuze.
Newproduct zou ik anders doen, ik zou de functie omschrijven naar Save($entity); en hem daar laten uitzoeken of het een nieuw record is of al een bestaande.

Dan kun je ook het volgende doen:
PHP:
1
2
3
4
5
$product = new Product();
$product->setName('test');
// nog wat attributen setten

$productRepository->Save($product);


Je kan onderwater een attribuut meenemen welke aangeeft of het een nieuw record of bestaand is. Of in de productRepository een lijst met bestaande producten (hash van een class) zie: http://php.net/manual/en/function.spl-object-hash.php . Als de hash van het product niet in de tabel voorkomt dan is hij nieuw en kun je een insert query schrijven, anders een update query.

Zodoende hoef je na een tijdje geen queries te schrijven. Als je de class hebt gedefinieerd dan doet de repository de rest van het werk wel voor je.

Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
ThomasG schreef op vrijdag 11 november 2016 @ 19:04:
[...]
Een beetje moderne PHP IDE kan anders prima met dynamische data omgaan. Steker nog, phpDoc bied daar functionaliteit voor.
Als je een object maakt met magic properties ja, maar je kan niet een plain array phpdocs geven (waar het in dit geval dus over ging)

Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
Barryvdh schreef op vrijdag 11 november 2016 @ 19:20:
[...]

Als je een object maakt met magic properties ja, maar je kan niet een plain array phpdocs geven (waar het in dit geval dus over ging)
Die je dus eenvoudig kunt mappen naar properties, waardoor je ook relaties eenvoudig kunt regelen. En meer mogelijkheden met je attributen.

Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
ThomasG schreef op vrijdag 11 november 2016 @ 19:22:
[...]
Die je dus eenvoudig kunt mappen naar properties, waardoor je ook relaties eenvoudig kunt regelen. En meer mogelijkheden met je attributen.
Dat is exact wat wij ook zeggen dus, mooi dat we het daar over eens zijn ;)

Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
Barryvdh schreef op vrijdag 11 november 2016 @ 19:33:
[...]

Dat is exact wat wij ook zeggen dus, mooi dat we het daar over eens zijn ;)
Volgens mij werd hier juist gezegd dat je moet getters en setters, in de zin van $person->getFirstName() ed. aanmaken. En dat is gewoon niet zo. Je kunt dat prima dat prima dynamisch met $person->firstName regelen, aan de hand van __get en __set.

Acties:
  • 0 Henk 'm!

  • Bee.nl
  • Registratie: November 2002
  • Niet online

Bee.nl

zoemt

ThomasG schreef op vrijdag 11 november 2016 @ 19:22:
[...]
Die je dus eenvoudig kunt mappen naar properties, waardoor je ook relaties eenvoudig kunt regelen. En meer mogelijkheden met je attributen.
Dat je ze kunt mappen naar properties begrijp ik, maar het ging me inderdaad om het werken met plain arrays. Het gebruik van arrays aan de input kant (array => object mapper) of aan de output kant (object als array weergeven) is niet meer dan logisch gebruik. Alles wat daartussen zit (business logic) zou idealiter via objecten lopen.

Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
ThomasG schreef op vrijdag 11 november 2016 @ 19:38:
[...]
Volgens mij werd hier juist gezegd dat je moet getters en setters, in de zin van $person->getFirstName() ed. aanmaken. En dat is gewoon niet zo. Je kunt dat prima dat prima dynamisch met $person->firstName regelen, aan de hand van __get en __set.
Thuis maak ik daar ook gebruik van, maar meer omdat ik er nog een laag tussen zit. Via comments voeg ik extra info toe aan de variabel, bijvoorbeeld:
PHP:
1
2
3
4
5
6
7
8
class Person extends Object
{
  /**
   * @var string
   * @field FirstName
  **/
  protected $_FirstName;
}


Via via regelt ObjectManager het setten en getten van waardes. Zo kan ik ook types checken int krijgt string? ArgumentException! Door @readonly toe te voegen kan ik het attribuut alleen lezen maken.
Overhead ja, maar wel super cool :)

Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 23-09 14:00
4Real schreef op vrijdag 11 november 2016 @ 19:45:
[...]

Thuis maak ik daar ook gebruik van, maar meer omdat ik er nog een laag tussen zit. Via comments voeg ik extra info toe aan de variabel, bijvoorbeeld:
PHP:
1
2
3
4
5
6
7
8
class Person extends Object
{
  /**
   * @var string
   * @field FirstName
  **/
  protected $_FirstName;
}


Via via regelt ObjectManager het setten en getten van waardes. Zo kan ik ook types checken int krijgt string? ArgumentException! Door @readonly toe te voegen kan ik het attribuut alleen lezen maken.
Overhead ja, maar wel super cool :)
Hiervoor zijn juist de @property, @property-read en @property-write tags. Zodat je iets krijgt als:
PHP:
1
2
3
4
5
6
7
8
/**
 * @property string $firstName
 * @property DateTime $birthdate
 * @property-read int $age
 */
class Person extends Model {
    // ...
}
Wat bijvoorbeeld prima werkt in combinatie met Laravel. En met een goede editor, werken zaken als auto complete, refactoring ed. zonder probleemn.

Acties:
  • +1 Henk 'm!

  • Bee.nl
  • Registratie: November 2002
  • Niet online

Bee.nl

zoemt

ThomasG schreef op vrijdag 11 november 2016 @ 19:38:
[...]
Volgens mij werd hier juist gezegd dat je moet getters en setters, in de zin van $person->getFirstName() ed. aanmaken. En dat is gewoon niet zo. Je kunt dat prima dat prima dynamisch met $person->firstName regelen, aan de hand van __get en __set.
Ik zit dagelijks in phpstorm met magic (legacy) code te stoeien en uit ervaring kan ik vertellen dat dit in grotere applicaties makkelijk tot (onnodige) issues kan leiden. Daarom wil ik graag benadrukken dit zo veel mogelijk te mijden tenzij dit noodzakelijk is voor een specifieke casus.
  • Usages tracken wordt bemoeilijkt. Een IDE als phpstorm kan veel, maar dynamic properties resolven is relatief beperkt.
  • Een expliciete setter kan type hints bevatten om te voorkomen dat het verkeerde type in de methode belandt. Het is niet tof wanneer een fout pas tig niveaus dieper in de stack trace een fatal oplevert. Denk aan het meegeven van een scalar terwijl het een array moest zijn. In het slechtste geval vindt er verderop ook nog een implicit cast plaats (object naar string bijv). In php7 kan dit nog stricter door de toevoeging van scalar argument type hints en return type hints.
  • Expliciete getters/setters kun je phpdoc geven, wat de kans op fouten kleiner maakt doordat je meer informatie krijgt over de types, het gebruik en eventuele exceptions. Ik weet van het bestaan van @property af, maar het is beperkter dan een compleet docblock.
  • In een IDE kun je meteen doorklikken op de methode, zodat je gelijk de juiste plek bent.
  • Expliciete getter/setters bevordert single responsibility. Stel dat er ergens validatie benodigd is zou je bij magic getter/setters een soort if/else of switch moeten bouwen om bepaalde properties af te vangen.
  • Het uit elkaar houden van de getter en setter is iets lastiger als je usages van magic properties gaat zoeken.
  • De performance van magic methods ligt iets lager (20% op mn php5.5 bak). Het kán een rol spelen wanneer er heel veel properties opgevraagd worden.
  • Een goede IDE kan automatisch getters/setters genereren. Dus extra werk zou ook geen argument mogen zijn.

Acties:
  • +1 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 23:00
ThomasG schreef op vrijdag 11 november 2016 @ 19:38:
[...]
Volgens mij werd hier juist gezegd dat je moet getters en setters, in de zin van $person->getFirstName() ed. aanmaken. En dat is gewoon niet zo. Je kunt dat prima dat prima dynamisch met $person->firstName regelen, aan de hand van __get en __set.
Ah, nee mijn reactie was gericht over deze vraag:
HollowGamer schreef op vrijdag 11 november 2016 @ 00:26:
Wat is precies fout met een array gebruiken? Snap het punt van IDE's, maar waarom zou het niet mogen? Zeker tegenwoordig waar er steeds meer data bij komt, en het niet altijd hoeft te zijn dat een object alles bevat. [..]
Ik ben er zelf ook een voorstand voor om gewoon dynamisch properties aan te roepen, in plaats van overal getter/setters te schrijven, maar dat is ook een kwestie van persoonlijke voorkeur. Daarop inhakend:
4Real schreef op vrijdag 11 november 2016 @ 19:18:
[..]

Je product variabelen zijn public, maar je hebt ook weer een get wrapper voor één van de variabelen. Wees consitent, ga voor get/set wrappers (en verberg de variabelen middels protected of private), of houdt ze allemaal public.
[..]
Ben ik het opzich ook mee eens, maar in dit voorbeeld geeft hij juist niet de onderliggende data terug, maar een aangepast. Nu is het voorbeeld van htmlentities juist niet zo handig, omdat dit iets wat je eigenlijk in je presentatie laag stopt, niet in je model. Maar bijv. een berekende prijs met korting, is wel iets wat hier goed kan. Wat mij betreft is het dan vaak leesbaar om hier een functie van te maken, zodat je ook ziet dat het niet zomaar de platte data is uit de database.

Ik ben wat dat betreft wel fan van de werkwijze van Laravel/Eloquent (Active Record style), heeeeeel versimpeld zoiets als hieronder. Maar zoals Bee.nl al zegt, dat is wel lastiger om terug te zoeken.

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
<?php

class Model
{
    protected $attributes;

    public function __construct(array $attributes)
    {
        $this->attributes = $attributes;
    }
    
    public function __get($name)
    {
        if (method_exists($this, 'get'.ucfirst($name).'Attribute')) {
            return $this->{'get'.ucfirst($name).'Attribute'}();
        }

        if (isset($this->attributes[$name])) {
            return $this->attributes[$name];
        }
    }

    public function __set($name, $value)
    {
        $this->attributes[$name] = $value;
    }
}

/**
 * @property $firstname;
 * @property $lastname;
 * @property-read $fullname;
 */
class Student extends Model
{
    public function getFullnameAttribute()
    {
        return $this->attributes['firstname'] . ' '  . $this->attributes['lastname'];
    }
}

$student = new Student([
    'firstname' => 'Berry',
    'lastname' => 'vd. H',
]);

$student->firstname = 'Barry';

var_dump($student->firstname);
var_dump($student->fullname);


phpdocs kan je natuurlijk ook gewoon laten genereren op basis van je database en als je maar duidelijke conventies afspreekt hoeft het ook geen probleem te zijn om dat terug te zoeken.

[ Voor 8% gewijzigd door Barryvdh op 11-11-2016 20:31 ]


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Ik ben ook duidelijk meer voorstander van expliciete getters/setters, die functies kan een goede IDE direct voor je maken en je zal nooit properties aanroepen die er niet zijn en verschilt imo niet veel van het gebruik van arrays meer dan. Het is net even wat stricter en daar hou ik van, magic methods probeer ik ten alle tijde te vermijden.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik lees veel terug over Laravel, en heb zelf ook even op het internet gekeken.
Maar is het voor een zeer simpele webshop of website wel handig om zo'n heel framework erbij te pakken?
Pagina: 1 2 Laatste