Doe ik OOP goed?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Ventilatiesysteem Productontwikkelaar HBO WO Verwa

Samengevat: Zij bieden flexibele ventilatiematerialen, geluidsdempers, rookgasafvoer producten en industrieslangen. Ben jij een technisch productontwikkelaar? Heb jij ervaring met het ontwikkelen van nieuwe producten? Vaste baan: Technisch Productontwikkelaar HBO WO €3.000 - €4.000 Zij bieden een variëteit aan flexibele ventilatiematerialen, geluiddempers, rookgasafvoer producten, industrieslangen en ventilatieslangen voor de scheepsbouw. Met slimme en innovatieve materialen zorgen wij voor een gezonde en frisse leefomgeving. Deze werkgever is een organisatie die volop in ontwikkeling is met hardwerkende collega's. Dit geeft goede ontwikkelingsmogelijkheden. De branche van dit bedrijf is Techniek en Engineering. Functie: Voor de vacature als Technisch Productontwikkelaar Ede Gld HBO WO ga

Bekijk vacature »

Pagina: 1 2 volgende »

- Rob -

- Rob -

26/12/2017 13:19:37
Quote Anchor link
Hallo,

Gister weer begonnen met OOP en ik had gister een login/register/passforget systeem gemaakt met OOP en ik vroeg mij af of ik het zo ongeveer goed deed en wat ik kan verbeteren.

De database users ziet er zo uit:
Afbeelding

databaseClass.php
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
    class Database
    {
        private $servername;
        private $username;
        private $password;
        private $database;
        private $conn;

        protected function connect()
        {

            if ($this->conn == NULL)
            {

                $this->servername = 'localhost';
                $this->username = 'root';
                $this->password = '';
                $this->database = 'oop';

                $this->conn = new mysqli($this->servername, $this->username, $this->password, $this->database);
            }

            
            return $this->conn;
        }
    }

?>


userClass.php
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
121
122
123
<?php
    class User extends Database
    {
        protected function generateRandomCode($length)
        {

            $unique = false;

            while (!$unique)
            {

                $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
                $charactersLength = strlen($characters);
                $randomCode = '';

                for ($i = 0; $i < $length; $i++)
                {

                    $randomCode .= $characters[rand(0, $charactersLength - 1)];
                }


                $sql = "SELECT `pcode` FROM `users` WHERE `change_ww_code` = '" . $this->connect()->real_escape_string($randomCode) . "'";
                $query = $this->connect()->query($sql);

                if ($query || $query->num_rows == 0)
                {

                    $unique = true;
                }
            }


            if ($unique == true)
            {

                return $randomCode;
            }
        }


        public function login($username, $password)
        {

            $sql = "SELECT `username`, `password`, `active` FROM `users` WHERE `username` = '" . $this->connect()->real_escape_string($username) . "'";
            $query = $this->connect()->query($sql);

            if ($query->num_rows == 0)
            {

                throw new Exception("De inlog gegevens zijn onjuist.");
            }

            else
            {
                $data = $query->fetch_assoc();

                if ($data['active'] == 0)
                {

                    throw new Exception("Je account is gedeactiveerd, neem contact op met een administrator.");
                }

                elseif (password_verify($password, $data['password']) == true)
                {

                    $sql = "UPDATE `users` SET `password` = '" . password_hash($password, PASSWORD_BCRYPT) . "', `last_online` = '" . date('Y-m-d H:i:s') . "', `change_ww_code` = '', `change_ww_perm` = '0' WHERE `username` = '" . $this->connect()->real_escape_string($username) . "'";
                    $query = $this->connect()->query($sql);
                }

                else
                {
                    throw new Exception("De inlog gegevens zijn onjuist.");
                }
            }
        }


        public function register($username, $password, $passwordrepeat)
        {

            $sql = "SELECT `username`, `password` FROM `users` WHERE `username` = '" . $this->connect()->real_escape_string($username) . "'";
            $query = $this->connect()->query($sql);

            if ($query->num_rows == 1)
            {

                throw new Exception("De gebruikersnaam is ongeldig.");
            }

            elseif ($password != $passwordrepeat || strlen($password) <= 5)
            {

                throw new Exception("Controleer de wachtwoorden of ze overeenkomen en 6 tekens of langer zijn.");
            }

            else
            {
                $sql = "INSERT INTO `users` (`username`, `password`, `register_date`) VALUE ('" . $this->connect()->real_escape_string($username) . "', '" . password_hash($password, PASSWORD_BCRYPT) . "', '" . date('Y-m-d H:i:s') . "')";
                $query = $this->connect()->query($sql);
                if (!$query)
                {

                    throw new Exception("Er is iets fout gegaan, neem contact op met een administrator.");
                }
            }
        }


        public function passForget($username, $password, $passwordrepeat, $code)
        {

            $sql = "SELECT `username`, `change_ww_perm`, `change_ww_code` FROM `users` WHERE `username` = '" . $this->connect()->real_escape_string($username) . "'";
            $query = $this->connect()->query($sql);

            if ($query->num_rows == 0)
            {

                throw new Exception("De gebruikersnaam is ongeldig.");
            }

            else
            {
                $data = $query->fetch_assoc();
                if ($password != $passwordrepeat || strlen($password) <= 5)
                {

                    throw new Exception("Controleer de wachtwoorden of ze overeenkomen en 6 tekens of langer zijn.");
                }

                elseif ($data['change_ww_perm'] == 0)
                {

                    throw new Exception("Je hebt geen toestemming om je wachtwoord te veranderen.");
                }

                elseif (!isset($code) || $code != $data['change_ww_code'])
                {

                    throw new Exception("De opgegeven code is onjuist.");
                }

                else
                {
                    $sql = "UPDATE `users` SET `password` = '" . password_hash($password, PASSWORD_BCRYPT) . "', `change_ww_perm` = '', `change_ww_code` = '' WHERE `username` = '" . $this->connect()->real_escape_string($username) . "'";
                    $query = $this->connect()->query($sql);
                    if (!$query)
                    {

                        throw new Exception("Er is iets fout gegaan, neem contact op met een administrator.");
                    }
                }
            }
        }
    }

?>


Ik weet niet of ik teveel if/elseif/else statements heb zo ja, zouden jullie mij dan kunnen vertellen hoe ik dit kan verbeteren :)

Graag hoor ik verbeter punten.

Mvg,
Rob
 
PHP hulp

PHP hulp

24/11/2024 08:16:03
 
- Ariën  -
Beheerder

- Ariën -

26/12/2017 14:14:37
Quote Anchor link
Het extenden klopt sowieso al niet. Want jij zegt dat een User een soort Database is.

Leuk leesvoer:
https://www.phphulp.nl/php/tutorial/overig/object-georinteerd-denken/632/inheritance/1666/
 
- Rob -

- Rob -

26/12/2017 14:28:39
Quote Anchor link
Volgens youtube https://www.youtube.com/watch?v=PHiu0JA9eqE kan dit wel gewoon. Dus dat filmpje heeft het fout? En hoe moet ik dan zorgen dat de User class de database connectie kan gebruiken? Moet ik daarvoor global $conn gebruiken, maar global is volgens vele mensen niet veilig..
Gewijzigd op 26/12/2017 14:43:18 door - Rob -
 
- Ariën  -
Beheerder

- Ariën -

26/12/2017 15:03:23
Quote Anchor link
Dat het in PHP kan, wil niet zeggen dat het juist is. Het filmpje heeft het dan ongetwijfeld behoorlijk fout.
De beste oplossing is om de instance van de database-class te voeren aan als argument aan je User-class.
 
- Rob -

- Rob -

26/12/2017 15:07:49
Quote Anchor link
Zou u misschien ergens een voorbeeld willen neerzetten? Ik heb het opgezocht maar snap niet precies wat ze aan het doen zijn.
 
Thomas van den Heuvel

Thomas van den Heuvel

26/12/2017 15:40:20
Quote Anchor link
Misschien moet je ook exceptions iets anders gaan zien.

Een exception treedt op (of zou op moeten treden) als er iets onverwachts gebeurt waarbij het mogelijk niet direct duidelijk is hoe verder te gaan, en soms staat het ter discussie of het uberhaupt mogelijk is om verder te kunnen gaan.

Dit is natuurlijk een groot grijs gebied, maar als je bijvoorbeeld naar je login-methode kijkt dan ligt het in zekere zin in de lijn der verwachting dat het inloggen wel eens mis kan gaan om een aantal uiteenlopende redenen. Ik weet echter niet of je deze zou moeten classificeren als exceptions, want je weet op dat moment precies wat er gebeurt, en wat er mis is gegaan.

En dan is het de vraag of je in dit geval de gebruiker (lees: potentiële aanvaller) uit moet leggen wat er precies misgaat. Je zou ook kunnen volstaan met een bericht -naar de gebruiker toe- dat de login simpelweg is mislukt, en dat deze het nogmaals moet proberen. Ondertussen zou je de (mislukte en geslaagde) loginpoging(en) kunnen loggen waarbij je uitgebreidere informatie bijhoudt.

Dan over methoden: deze voeren meestal een enkele taak uit, maar dat hoeft niet in te houden dat dit altijd weinig code is. Het moet natuurlijk wel een duidelijk afgebakend gebied zijn. De passForget-methode is een beetje vreemd: als iemand een recht niet heeft, geef deze persoon dan simpelweg de keuze niet om iets te kunnen wijzigen. Ook zou je hier eigenlijk van database-transacties gebruik moeten maken: de informatie die je mogelijk aanpast in de methode moet gedurende die methode vergrendeld zijn.

Over regels 72 en 99: daar wordt twee keer eenzelfde conditie vastgelegd waar een wachtwoord aan moet voldoen: ten minste 6 karakters. Wat als je dadelijk meer regels hebt? Deze moet je eigenlijk op één plaats vastleggen zodat je deze ook op één plaats kunt wijzigen. Als je code groeit heb je straks op tig plaatsen allerlei (en in het ergste geval: verschillende) condities waar wachtwoorden aan zouden moeten voldoen.

Over de database class: vraag jezelf af wat de meerwaarde van het opslaan van connectie-parameters is. Wat mij betreft id die er niet echt. Het is nogal raar dat $conn private is, maar je daar wel -buiten het object om, en daarmee in feite dus rechtstreeks via de mysqli-class- mee communiceert.

Op dit moment heeft de database-class niet echt veel toegevoegde waarde, het neemt niet echt veel werk uit handen. Dit verandert natuurlijk wanneer je deze class wat verder uitbreidt. Kijk bijvoorbeeld voor inspiratie in deze thread (moet link even opsnorren omdat ik mijn eigen topics niet kan vinden met zoekfunctionaliteit -_-). EDIT: in grote lijnen gebruik ik deze classes (hier en daar enkele toevoegingen) nog steeds voor wat eigen projectjes. Eigenlijk het belangrijkste is dat je een CHARACTER ENCODING instelt bij het maken van een connectie.
Gewijzigd op 26/12/2017 16:06:53 door Thomas van den Heuvel
 
Nick Vledder

Nick Vledder

26/12/2017 15:47:14
Quote Anchor link
- Ariën - op 26/12/2017 14:14:37:
Het extenden klopt sowieso al niet. Want jij zegt dat een User een soort Database is.


Zou je User niet kunnen zien als een representatie van een deel van de database? De kinderen delen daarbij de gemeenschappelijke connectie zoals gedefinieerd in de parent?

EDIT: toevoeging... ik wil de topicstarter (Rob) niet meteen overladen, maar ik zie dat de User-class zowel de database benadert als ook de opgevraagde data verwerkt. Een veelgebruikt design-pattern is MVC: Model - View - Control.
Gewijzigd op 26/12/2017 15:53:42 door Nick Vledder
 
- Rob -

- Rob -

26/12/2017 16:01:24
Quote Anchor link
Thomas van den Heuvel op 26/12/2017 15:40:20:
Misschien moet je ook exceptions iets anders gaan zien.

Een exception treedt op (of zou op moeten treden) als er iets onverwachts gebeurt waarbij het mogelijk niet direct duidelijk is hoe verder te gaan, of dat men uberhaupt verder kan gaan.

Dit is natuurlijk een groot grijs gebied, maar als je bijvoorbeeld naar je login-methode kijkt dan ligt het in zekere zin in de lijn der verwachting dat het inloggen wel eens mis kan gaan om een aantal uiteenlopende redenen. Ik weet echter niet of je deze zou moeten classificeren als exceptions, want je weet op dat moment precies wat er gebeurt, en wat er mis is gegaan.

En dan is het de vraag of je in dit geval de gebruiker (lees: potentiële aanvaller) uit moet leggen wat er precies misgaat. Je zou ook kunnen volstaan met een bericht -naar de gebruiker toe- dat de login simpelweg is mislukt, en dat deze het nogmaals moet proberen. Ondertussen zou je de (mislukte en) loginpoging(en) kunnen loggen waarbij je uitgebreidere informatie bijhoudt.

Dan over methoden: deze voeren meestal een enkele taak uit, maar dat hoeft niet in te houden dat dit altijd weinig code is. Het moet natuurlijk wel een duidelijk afgebakend gebied zijn. De passForget-methode is een beetje vreemd: als iemand een recht niet heeft, geef deze persoon dan simpelweg de keuze niet om iets te kunnen wijzigen. Ook zou je hier eigenlijk van database-transacties gebruik moeten maken: de informatie die je mogelijk aanpast in de methode moet gedurende die methode vergrendeld zijn.

Over regels 72 en 99: daar wordt twee keer eenzelfde conditie vastgelegd waar een wachtwoord aan moet voldoen: ten minste 6 karakters. Wat als je dadelijk meer regels hebt? Deze moet je eigenlijk op één plaats vastleggen zodat je deze ook op één plaats kunt wijzigen. Als je code groeit heb je straks op tig plaatsen allerlei (en in het ergste geval: verschillende) condities waar wachtwoorden aan zouden moeten voldoen.

Over de database class: vraag jezelf af wat de meerwaarde van het opslaan van connectie-parameters is. Wat mij betreft id die er niet echt. Het is nogal raar dat $conn private is, maar je daar wel -buiten het object om, en daarmee in feite dus rechtstreeks via de mysqli-class- mee communiceert.

Op dit moment heeft de database-class niet echt veel toegevoegde waarde, het neemt niet echt veel werk uit handen. Dit verandert natuurlijk wanneer je deze class wat verder uitbreidt. Kijk bijvoorbeeld voor inspiratie in deze thread (moet link even opsnorren omdat ik mijn eigen topics niet kan vinden met zoekfunctionaliteit -_-). EDIT: in grote lijnen gebruik ik deze classes (hier en daar enkele toevoegingen) nog steeds voor wat eigen projectjes. Eigenlijk het belangrijkste is dat je een CHARACTER ENCODING instelt bij het maken van een connectie.


De expcetions doe ik omdat dit mij is is verteld in een van mijn eerdere topics.

Als dit is zo bij het inloggen, maar bij het registreren moeten ze wel weten waarom hun wachtwoord niet goed is, anders blijven ze het maar proberen, of niet?

Ik heb $conn private gemaakt zodat alleen DIE class er iets mee kan doen, via connect() kan ik dan vervolgens het gaan gebruiken in andere classen


Toevoeging op 26/12/2017 16:05:53:

- Ariën - op 26/12/2017 15:03:23:
Dat het in PHP kan, wil niet zeggen dat het juist is. Het filmpje heeft het dan ongetwijfeld behoorlijk fout.
De beste oplossing is om de instance van de database-class te voeren aan als argument aan je User-class.


Zou ik bv. ook aan Mapper kunnen gebruiken, zie deze thread: https://www.phphulp.nl/php/forum/topic/oop/100868/ (ergens onderaan)
 
Thomas van den Heuvel

Thomas van den Heuvel

26/12/2017 16:12:48
Quote Anchor link
Quote:
De expcetions doe ik omdat dit mij is is verteld in een van mijn eerdere topics.

If it's on the internet, it must be true.

Quote:
Als dit is zo bij het inloggen, maar bij het registreren moeten ze wel weten waarom hun wachtwoord niet goed is, anders blijven ze het maar proberen, of niet?

Ja, maar dat maakt het nog geen exception. Ongeldige invoer in een formulier is niet (of in ieder geval niet per definitie) een exception. Dit resulteert enkel in het niet slagen van een validatie, maar de code weet precies wat er vervolgens moet gebeuren: foutmeldingen terugsturen naar de gebruiker. Hier is dus geen sprake van code die spaak loopt doordat er iets onverwachts is gebeurd, maar omdat de gebruiker ongeldige invoer heeft ingevuld. Dit ligt dus in de lijn der verwachting en als het goed is heb je hier ook een (gebruiksvriendelijke) afhandeling voor. Exception zijn juist voor situaties waarbij je niet (direct) weet hoe verder te gaan.

Quote:
Ik heb $conn private gemaakt zodat alleen DIE class er iets mee kan doen, via connect() kan ik dan vervolgens het gaan gebruiken in andere classen

Ja, je retourneert (een private) $this->conn, en dat is niets meer dan een mysqli-object. Dus waarom werk je daar dan niet rechtstreeks mee :p. Je kunt ook ergens gewoon een variabele $db die je doorgeeft aan andere objecten. Maar $db is dan wel van de klasse Database (je wrapper), en niet van mysqli, die enkel in Database intern wordt gebruikt...

EDIT: het is op zijn minst een verkeerde gebruik van private, want dat ding is -in het gebruik- niet private, je mikt het gewoon de buitenwereld in middels return $this->conn. Hiermee schep je een verkeerd beeld van $conn.
Gewijzigd op 26/12/2017 16:15:15 door Thomas van den Heuvel
 
- Rob -

- Rob -

26/12/2017 16:15:01
Quote Anchor link
"If it's on the internet, it must be true."
Dat niet persee maar Ariën had mij dit gezegd.

Hoe zou ik anders die fouten moeten afhandelen? Echo is niet netjes.
 
Thomas van den Heuvel

Thomas van den Heuvel

26/12/2017 16:17:40
Quote Anchor link
Maak een Form class waarmee je een formulier+velden kunt opbouwen, valideren etc? :]

Zou je ook eerst zonder classes/objecten kunnen doen. In zijn simpelste vorm:

toon Form (al dan niet met foutmeldingen bij de velden met verkeerde invoer van eerdere pogingen)
<verstuur>
validatie van form
ok -> verwerk -> stuur door naar bedankpagina/overzicht/whatever
niet ok -> sla fouten op (bijvoorbeeld in sessie), terug naar toon Form

En fouten op het scherm dumpen is niet echt afhandelen he, da's meer debug :).
Gewijzigd op 26/12/2017 16:19:06 door Thomas van den Heuvel
 
- Rob -

- Rob -

26/12/2017 16:19:47
Quote Anchor link
Dit had ik al eens eerder gemaakt, werkte prima.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
function getValue($key, $return = false)
    {
        $lines_array = file($_SERVER['DOCUMENT_ROOT'] . '/Workspace/Novara Bank/paneel/assets/text.txt');

        foreach ($lines_array as $line)
        {
            $values = explode(': ', $line);

            if (trim($values[0]) == $key)
            {
                if ($return == true)
                {
                    return $values[1];
                }
                else
                {
                    echo $values[1];
                }
            }
        }
    }

if (isset($_POST['type']))
    {
        if ($_POST['type'] == 'login')
        {
            $searchUserSql = $mysqli->query(
                                            "SELECT *
                                            FROM `leden`
                                            WHERE `gebruikersnaam` = '" . save_string($_POST['username']) . "'
                                            ORDER BY `id`
                                            DESC
                                            LIMIT 1"
                                           );

            if (
                !$searchUserSql
                || $searchUserSql->num_rows == 0
               )
            {
                getValue('wrong_login');
            }
            else
            {
                $userDetails = $searchUserSql->fetch_assoc();

                if (!password_verify($_POST['password'], $userDetails['wachtwoord']))
                {
                    getValue('wrong_login');
                }
                elseif ($userDetails['actief'] === 0)
                {
                    getValue('inactive_login');
                }
                else
                {
                    if (createNewLog('heeft zichzelf ingelogd', $userDetails['id']) == false)
                    {
                        getValue('error');
                    }
                    else
                    {
                        $updateUserDetailsSql = $mysqli->query(
                                                               "UPDATE `leden`
                                                               SET `wachtwoord` = '" . save_string(password_hash($_POST['password'], PASSWORD_BCRYPT)) . "',
                                                               `laatst_online` = '" . save_string(date('H:i:s d-m-Y', time())) .  "'"
                                                              );
                        if (!$updateUserDetailsSql)
                        {
                            getValue('error');
                        }
                        else
                        {
                            $_SESSION['gebruikerInfo'] = $userDetails;
                            $_SESSION['gebruikerInfo']['wachtwoord'] = '';
                            getValue('success_login');
                        }
                    }
                }
            }
        }

$(".form-l-submit").click(function() {
                    var username = $(".form-l-username").val();
                    var password = $(".form-l-password").val();
                    var dataString = 'username=' + username + '&password=' + password + '&type=login';

                    if (!username.trim() || !password.trim()) {
                        $('.message').addClass('callout callout-danger');
                        $('.message').html('Je hebt niet alle velden ingevuld.');
                        setTimeout(function() {
                            $('.message').removeClass('callout callout-danger');
                            $('.message').html('');
                        }, 5000);
                    } else {
                        $.ajax({
                            type: "POST",
                            url: "/Workspace/Novara Bank/paneel/includes/actions.php",
                            data: dataString,
                            cache: false,
                            success: function(result) {
                                if (result.includes("Je bent met succes ingelogd.") == true) {
                                    location.reload();
                                }
                                 else
                                {
                                    $('.message').addClass('callout callout-danger');
                                    $('.message').html(result);
                                    setTimeout(function() {
                                        $('.message').removeClass('callout callout-danger');
                                        $('.message').html('');
                                    }, 5000);
                                }
                            }
                        });
                    }
                    return false;
                });

Hier ging alles prima, maar wou verder met OOP
 
Thomas van den Heuvel

Thomas van den Heuvel

26/12/2017 16:29:36
Quote Anchor link
Los van de vorm waarin je dit giet (oop, procedureel), je bent hier meerdere dingen (inloggen, updaten van wachtwoord?!) tegelijkertijd aan het doen. Het lijkt mij belangrijk om dingen op te splitsen in verschillende acties.

Ook kan het handig zijn om dingen om te draaien (EDIT: beter gezegd: het gebruik van negaties te voorkomen als dit mogelijk is), in plaats van:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
if (!C) {
  A
} else {
  B
}

Zou je ook, en wellicht beter, dit kunnen doen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
if (C) {
  B
} else {
  A
}

Of op zijn minst de ! explicieter kunnen maken, bijvoorbeeld door:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
if (C === false) {
  A
} else {
  B
}

(of false === C, whatever floats your boat)

Ook staat er geen letter annotatie in je code, dus dit is ook vrij moeilijk leesbaar/interpreteerbaar door mensen die deze code niet hebben geschreven omdat het doel/de bedoeling niet is gespecificeerd.
Gewijzigd op 26/12/2017 16:34:56 door Thomas van den Heuvel
 
- Rob -

- Rob -

26/12/2017 16:35:11
Quote Anchor link
Oké, bedankt. Wat is letter anootatie? Zijn dat comments?
 
- Ariën  -
Beheerder

- Ariën -

26/12/2017 16:40:03
 
Jan Koehoorn

Jan Koehoorn

26/12/2017 17:45:41
Quote Anchor link
De vraagstelling is natuurlijk heel algemeen: "Doe ik OOP goed?"

Ik programmeer al een jaar of dertig, en het verbetert nog elk jaar. De inzichten en technieken die als "goed" beschouwd worden veranderen ook elk jaar. Los van de hypes die langskomen, is er wel een aantal vuistregels te geven die ik je wil meegeven als je OOP wilt programmeren.

Single Responsibility Principle: hou je classes kort en je methods klein. Zorg dat een method maar 1 ding heel goed doet, en meer niet. Dit principe is onderdeel van SOLID (er zijn dus 5 principes)

Lees iets over loose coupling en depency injection.

Wees voorzichtig met child classes en inheritance. Je kunt een class beter samenstellen door hem verschillende interfaces te laten implementeren dan dat je heel veel parent en child relaties creëert. Dit principe heet "composition over inheritance".

Helden op dit gebied: Uncle Bob, Taylor Otwell, Jeffrey Way, Eric Evans.

Tot slot: OOP en Design Patterns leer je niet in een maand, daarom is het zo leuk. Je blijft steeds maar dingen bij leren.
Gewijzigd op 26/12/2017 20:20:42 door Jan Koehoorn
 
- Rob -

- Rob -

26/12/2017 19:21:39
Quote Anchor link
Bedankt voor jullie reacties!

Jan Koehoorn, ik programmeer nu 1 jaar met een pauze van ongeveer 6 maanden (sinds gister begonnen weer) en ik hoop dat ik veel nog kan leren over programmeren :)
 
Thomas van den Heuvel

Thomas van den Heuvel

26/12/2017 20:43:10
Quote Anchor link
- Rob - op 26/12/2017 16:35:11:
Oké, bedankt. Wat is letter anootatie? Zijn dat comments?

Ja commentaarregels of -blokken, dan kun je iig aanhalen wat de bedoeling was. Iemand anders kan dan oordelen of jouw code ook doet wat het dient te doen. Als je hier niks over opschrijft wordt dat behoorlijk lastig.

En tis ook handig als je zelf na X dagen, maanden, jaren nog eens iets terugzoekt en dan kan zien wat (eigenlijk) de bedoeling was.
Gewijzigd op 26/12/2017 20:44:22 door Thomas van den Heuvel
 
Ozzie PHP

Ozzie PHP

26/12/2017 23:15:30
Quote Anchor link
Nick Vledder op 26/12/2017 15:47:14:
Zou je User niet kunnen zien als een representatie van een deel van de database?

Nee, een User is niet (een onderdeel van) een database. Het is slechts inhoud die door de database wordt vastgehouden. Een chauffeur of een passagier is ook geen (onderdeel van een) auto.
 
- Rob -

- Rob -

27/12/2017 19:27:55
Quote Anchor link
Hey,

Is dit een goede database class?:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
<?php
/**
 * Exception helper for the Database class
 */

class DatabaseException extends Exception
{
    // Default Exception class handles everything
}
/**
 * A basic database interface using MySQLi
 */

class Database
{
    private $sql;
    private $mysql;
    private $result;
    private $result_rows;
    private $database_name;
    private static $instance;
    /**
     * Query history
     *
     * @var array
     */

    static $queries = array();
    /**
     * Database() constructor
     *
     * @param string $database_name
     * @param string $username
     * @param string $password
     * @param string $host
     * @throws DatabaseException
     */

    function __construct($database_name, $username, $password, $host = 'localhost')
    {

        self::$instance = $this;
        $this->database_name = $database_name;
        $this->mysql = mysqli_connect($host, $username, $password, $database_name);
        if (!$this->mysql) {
            throw new DatabaseException('Database connection error: ' . mysqli_connect_error());
        }
    }

    /**
     * Get instance
     *
     * @param string $database_name
     * @param string $username
     * @param string $password
     * @param string $host
     * @return Database
     */

    final public static function instance($database_name = null, $username = null, $password = null, $host = 'localhost')
    {

        if (!isset(self::$instance)) {
            self::$instance = new Database($database_name, $username, $password, $host);
        }

        return self::$instance;
    }

    /**
     * Helper for throwing exceptions
     *
     * @param $error
     * @throws Exception
     */

    private function _error($error)
    {

        throw new DatabaseException('Database error: ' . $error);
    }

    /**
     * Turn an array into a where statement
     *
     * @param mixed $where
     * @param string $where_mode
     * @return string
     * @throws Exception
     */

    public function process_where($where, $where_mode = 'AND')
    {

        $query = '';
        if (is_array($where)) {
            $num = 0;
            $where_count = count($where);
            foreach ($where as $k => $v) {
                if (is_array($v)) {
                    $w = array_keys($v);
                    if (reset($w) != 0) {
                        throw new Exception('Can not handle associative arrays');
                    }

                    $query .= " `" . $k . "` IN (" . $this->join_array($v) . ")";
                }
elseif (!is_integer($k)) {
                    $query .= ' `' . $k . "`='" . $this->escape($v) . "'";
                }
else {
                    $query .= ' ' . $v;
                }

                $num++;
                if ($num != $where_count) {
                    $query .= ' ' . $where_mode;
                }
            }
        }
else {
            $query .= ' ' . $where;
        }

        return $query;
    }

    /**
     * Perform a SELECT operation
     *
     * @param string $table
     * @param array $where
     * @param bool $limit
     * @param bool $order
     * @param string $where_mode
     * @param string $select_fields
     * @return Database
     * @throws DatabaseException
     */

    public function select($table, $where = array(), $limit = false, $order = false, $where_mode = "AND", $select_fields = '*')
    {

        $this->result = null;
        $this->sql = null;
        if (is_array($select_fields)) {
            $fields = '';
            foreach ($select_fields as $s) {
                $fields .= '`' . $s . '`, ';
            }

            $select_fields = rtrim($fields, ', ');
        }

        $query = 'SELECT ' . $select_fields . ' FROM `' . $table . '`';
        if (!empty($where)) {
            $query .= ' WHERE' . $this->process_where($where, $where_mode);
        }

        if ($order) {
            $query .= ' ORDER BY ' . $order;
        }

        if ($limit) {
            $query .= ' LIMIT ' . $limit;
        }

        return $this->query($query);
    }

    /**
     * Perform a query
     *
     * @param string $query
     * @return $this|Database
     * @throws Exception
     */

    public function query($query)
    {

        self::$queries[] = $query;
        $this->sql = $query;
        $this->result_rows = null;
        $this->result = mysqli_query($this->mysql, $query);
        if (mysqli_error($this->mysql) != '') {
            $this->_error(mysqli_error($this->mysql));
            $this->result = null;
            return $this;
        }

        return $this;
    }

    /**
     * Get last executed query
     *
     * @return string|null
     */

    public function sql()
    {

        return $this->sql;
    }

    /**
     * Get an array of objects with the query result
     *
     * @param string|null $key_field
     * @return array
     */

    public function result($key_field = null)
    {

        if (!$this->result_rows) {
            $this->result_rows = array();
            while ($row = mysqli_fetch_assoc($this->result)) {
                $this->result_rows[] = $row;
            }
        }

        $result = array();
        $index = 0;
        foreach ($this->result_rows as $row) {
            $key = $index;
            if (!empty($key_field) && isset($row[$key_field])) {
                $key = $row[$key_field];
            }

            $result[$key] = new stdClass();
            foreach ($row as $column => $value) {
                $this->is_serialized($value, $value);
                $result[$key]->{$column} = $this->clean($value);
            }

            $index++;
        }

        return $result;
    }

    /**
     * Get an array of arrays with the query result
     *
     * @return array
     */

    public function result_array()
    {

        if (!$this->result_rows) {
            $this->result_rows = array();
            while ($row = mysqli_fetch_assoc($this->result)) {
                $this->result_rows[] = $row;
            }
        }

        $result = array();
        $n = 0;
        foreach ($this->result_rows as $row) {
            $result[$n] = array();
            foreach ($row as $k => $v) {
                $this->is_serialized($v, $v);
                $result[$n][$k] = $this->clean($v);
            }

            $n++;
        }

        return $result;
    }

    /**
     * Get a specific row from the result as an object
     *
     * @param int $index
     * @return stdClass
     */

    public function row($index = 0)
    {

        if (!$this->result_rows) {
            $this->result_rows = array();
            while ($row = mysqli_fetch_assoc($this->result)) {
                $this->result_rows[] = $row;
            }
        }

        $num = 0;
        foreach ($this->result_rows as $column) {
            if ($num == $index) {
                $row = new stdClass();
                foreach ($column as $key => $value) {
                    $this->is_serialized($value, $value);
                    $row->{$key} = $this->clean($value);
                }

                return $row;
            }

            $num++;
        }

        return new stdClass();
    }

    /**
     * Get a specific row from the result as an array
     *
     * @param int $index
     * @return array
     */

    public function row_array($index = 0)
    {

        if (!$this->result_rows) {
            $this->result_rows = array();
            while ($row = mysqli_fetch_assoc($this->result)) {
                $this->result_rows[] = $row;
            }
        }

        $num = 0;
        foreach ($this->result_rows as $column) {
            if ($num == $index) {
                $row = array();
                foreach ($column as $key => $value) {
                    $this->is_serialized($value, $value);
                    $row[$key] = $this->clean($value);
                }

                return $row;
            }

            $num++;
        }

        return array();
    }

    /**
     * Get the number of result rows
     *
     * @return bool|int
     */

    public function count()
    {

        if ($this->result) {
            return mysqli_num_rows($this->result);
        }
elseif (isset($this->result_rows)) {
            return count($this->result_rows);
        }
else {
            return false;
        }
    }

    /**
     * Execute a SELECT COUNT(*) query on a table
     *
     * @param null $table
     * @param array $where
     * @param bool $limit
     * @param bool $order
     * @param string $where_mode
     * @return mixed
     */

    public function num($table = null, $where = array(), $limit = false, $order = false, $where_mode = "AND")
    {

        if (!empty($table)) {
            $this->select($table, $where, $limit, $order, $where_mode, 'COUNT(*)');
        }

        $res = $this->row();
        return $res->{'COUNT(*)'};
    }

    /**
     * Check if a table with a specific name exists
     *
     * @param $name
     * @return bool
     */

    function table_exists($name)
    {

        $res = mysqli_query($this->mysql, "SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = '" . $this->escape($this->database_name) . "' AND table_name = '" . $this->escape($name) . "'");
        return ($this->mysqli_result($res, 0) == 1);
    }

    /**
     * Helper function for process_where
     *
     * @param $array
     * @return string
     */

    private function join_array($array)
    {

        $nr = 0;
        $query = '';
        foreach ($array as $key => $value) {
            if (is_object($value) || is_array($value) || is_bool($value)) {
                $value = serialize($value);
            }

            $query .= " '" . $this->escape($value) . "'";
            $nr++;
            if ($nr != count($array)) {
                $query .= ',';
            }
        }

        return trim($query);
    }

    /* Insert/update functions */
    /**
     * Insert a row in a table
     *
     * @param $table
     * @param array $fields
     * @param bool|false $appendix
     * @param bool|false $ret
     * @return bool|Database
     * @throws Exception
     */

    function insert($table, $fields = array(), $appendix = false, $ret = false)
    {

        $this->result = null;
        $this->sql = null;
        $query = 'INSERT INTO';
        $query .= ' `' . $this->escape($table) . "`";
        if (is_array($fields)) {
            $query .= ' (';
            $num = 0;
            foreach ($fields as $key => $value) {
                $query .= ' `' . $key . '`';
                $num++;
                if ($num != count($fields)) {
                    $query .= ',';
                }
            }

            $query .= ' ) VALUES ( ' . $this->join_array($fields) . ' )';
        }
else {
            $query .= ' ' . $fields;
        }

        if ($appendix) {
            $query .= ' ' . $appendix;
        }

        if ($ret) {
            return $query;
        }

        $this->sql = $query;
        $this->result = mysqli_query($this->mysql, $query);
        if (mysqli_error($this->mysql) != '') {
            $this->_error(mysqli_error($this->mysql));
            $this->result = null;
            return false;
        }
else {
            return $this;
        }
    }

    /**
     * Execute an UPDATE statement
     *
     * @param $table
     * @param array $fields
     * @param array $where
     * @param bool $limit
     * @param bool $order
     * @return $this|bool
     * @throws DatabaseException
     */

    function update($table, $fields = array(), $where = array(), $limit = false, $order = false)
    {

        if (empty($where)) {
            throw new DatabaseException('Where clause is empty for update method');
        }

        $this->result = null;
        $this->sql = null;
        $query = 'UPDATE `' . $table . '` SET';
        if (is_array($fields)) {
            $nr = 0;
            foreach ($fields as $k => $v) {
                if (is_object($v) || is_array($v) || is_bool($v)) {
                    $v = serialize($v);
                }

                $query .= ' `' . $k . "`='" . $this->escape($v) . "'";
                $nr++;
                if ($nr != count($fields)) {
                    $query .= ',';
                }
            }
        }
else {
            $query .= ' ' . $fields;
        }

        if (!empty($where)) {
            $query .= ' WHERE' . $this->process_where($where);
        }

        if ($order) {
            $query .= ' ORDER BY ' . $order;
        }

        if ($limit) {
            $query .= ' LIMIT ' . $limit;
        }

        $this->sql = $query;
        $this->result = mysqli_query($this->mysql, $query);
        if (mysqli_error($this->mysql) != '') {
            $this->_error(mysqli_error($this->mysql));
            $this->result = null;
            return false;
        }
else {
            return $this;
        }
    }

    /**
     * Execute a DELETE statement
     *
     * @param $table
     * @param array $where
     * @param string $where_mode
     * @param bool $limit
     * @param bool $order
     * @return $this|bool
     * @throws DatabaseException
     * @throws Exception
     */

    function delete($table, $where = array(), $where_mode = "AND", $limit = false, $order = false)
    {

        if (empty($where)) {
            throw new DatabaseException('Where clause is empty for update method');
        }

        // Notice: different syntax to keep backwards compatibility
        $this->result = null;
        $this->sql = null;
        $query = 'DELETE FROM `' . $table . '`';
        if (!empty($where)) {
            $query .= ' WHERE' . $this->process_where($where, $where_mode);
        }

        if ($order) {
            $query .= ' ORDER BY ' . $order;
        }

        if ($limit) {
            $query .= ' LIMIT ' . $limit;
        }

        $this->sql = $query;
        $this->result = mysqli_query($this->mysql, $query);
        if (mysqli_error($this->mysql) != '') {
            $this->_error(mysqli_error($this->mysql));
            $this->result = null;
            return false;
        }
else {
            return $this;
        }
    }

    /**
     * Get the primary key of the last inserted row
     *
     * @return int|string
     */

    public function id()
    {

        return mysqli_insert_id($this->mysql);
    }

    /**
     * Get the number of rows affected by your last query
     *
     * @return int
     */

    public function affected()
    {

        return mysqli_affected_rows($this->mysql);
    }

    /**
     * Escape a parameter
     *
     * @param $str
     * @return string
     */

    public function escape($str)
    {

        return mysqli_real_escape_string($this->mysql, $str);
    }

    /**
     * Get the last error message
     *
     * @return string
     */

    public function error()
    {

        return mysqli_error($this->mysql);
    }

    /**
     * Fix UTF-8 encoding problems
     *
     * @param $str
     * @return string
     */

    private function clean($str)
    {

        if (is_string($str)) {
            if (!mb_detect_encoding($str, 'UTF-8', TRUE)) {
                $str = utf8_encode($str);
            }
        }

        return $str;
    }

    /**
     * Check if a variable is serialized
     *
     * @param mixed $data
     * @param null $result
     * @return bool
     */

    public function is_serialized($data, &$result = null)
    {

        if (!is_string($data)) {
            return false;
        }

        $data = trim($data);
        if (empty($data)) {
            return false;
        }

        if ($data === 'b:0;') {
            $result = false;
            return true;
        }

        if ($data === 'b:1;') {
            $result = true;
            return true;
        }

        if ($data === 'N;') {
            $result = null;
            return true;
        }

        if (strlen($data) < 4) {
            return false;
        }

        if ($data[1] !== ':') {
            return false;
        }

        $lastc = substr($data, -1);
        if (';' !== $lastc && '}' !== $lastc) {
            return false;
        }

        $token = $data[0];
        switch ($token) {
            case
's' :
                if ('"' !== substr($data, -2, 1)) {
                    return false;
                }

                break;
            case
'a' :
            case
'O' :
                if (!preg_match("/^{$token}:[0-9]+:/s", $data)) {
                    return false;
                }

                break;
            case
'b' :
            case
'i' :
            case
'd' :
                if (!preg_match("/^{$token}:[0-9.E-]+;/", $data)) {
                    return false;
                }
        }

        try {
            if (($res = @unserialize($data)) !== false) {
                $result = $res;
                return true;
            }

            if (($res = @unserialize(utf8_encode($data))) !== false) {
                $result = $res;
                return true;
            }
        }
catch (Exception $e) {
            return false;
        }

        return false;
    }

    /**
     * MySQL compatibility method mysqli_result
     * http://www.php.net/manual/en/class.mysqli-result.php#109782
     *
     * @param mysqli_result $res
     * @param int $row
     * @param int $field
     */

    private function mysqli_result($res, $row, $field = 0)
    {

        $res->data_seek($row);
        $datarow = $res->fetch_array();
        return $datarow[$field];
    }
}
[
/code]
 
- Ariën  -
Beheerder

- Ariën -

27/12/2017 19:42:49
Quote Anchor link
Heb je die echt nodig?
In PHP heb je ook een standaard MySQLi of PDO-class die je kan gebruiken.

Persoonlijk vind ik een class maken een beetje het wiel opnieuw uitvinden. Je kan voor het gemak zelf ook een 'wrapper' maken zodat je zelf in je class kan beslissen of je MySQLi, PDO, Oracle of wat dan ook wilt gebruiken, zonder dat je heel je script moet aanpassen bij een wijziging.

Het is net hoever je wilt gaan, een hoeveel tijd je wilt investeren. De wereld van OOP is erg groot te noemen.
Gewijzigd op 27/12/2017 19:43:20 door - Ariën -
 

Pagina: 1 2 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.