Eerste OOP script [gastenboek]

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Gerhard l

gerhard l

28/02/2012 10:28:55
Quote Anchor link
Goedemorgen,

Na een aantal berichten hier op het forum hebben doorgelezen, ben ik me ook een beetje gaan verdiepen in OOP. Via deze site klik heb ik geprobeerd om een simpel gastenboek te maken, waar je tot nu toe alleen kan plaatsen, en weergeven.
De vraag is ben ik zo op de goede weg, en moet ik input nog verder beveiligen?
In ieder geval bedankt voor het lezen.

gastenboek.class.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
124
125
126
127
128
129
130
<?
class Gastenboek
{
    private $reacties;
    private $db;
    
    /* Verbindg maken, en de geplaatste reacties in een array stoppen */
    public function __construct(PDO $db)
    {

        $this->db = $db;
        
        $query = $this->db->prepare("SELECT * FROM bericht");
        $query->execute();
        
        while($row = $query->fetch(PDO::FETCH_ASSOC)){
            
            $this->reacties[] = $row;
        }
    }

  
    /* Toevoegen van een reactie, de gebruiker en reactie wordt meegegeven */
    public function reactie_toevoegen(Gebruiker $gebruiker, Reactie $reactie)
    {

        $this->reactie = $reactie;
        $this->gebruiker = $gebruiker;
        
        $query = $this->db->prepare("INSERT INTO bericht (
            naam,
            email,
            website,
            datum,
            reactie
    
        ) VALUES (
            :naam,
            :email,
            :website,
            now(),
            :bericht
        )"
);
        $query->execute(array(
            ':naam' => $gebruiker->getNaam(),
            ':email' => $gebruiker->getEmail(),
            ':website' => $gebruiker->getWebsite(),
            ':bericht' => $reactie->getReactie()
            )
        );

        
        /* Toevoegen aan de bestaande array */
        $array = array(
            'id' => $this->db->lastInsertId(),
            'naam' => $gebruiker->getNaam(),
            'email' => $gebruiker->getEmail(),
            'website' => $gebruiker->getWebsite(),
            'datum' => date('Y-m-d') . ' ' . date('H:i:s'),
            'reactie' => $reactie->getReactie()
        );

        
        $this->reacties[] = $array;
    }

    
    /* Reacties ophalen */
    public function weergeven()
    {

        return $this->reacties;
    }

    
    /* Formulier */
    public function getFormulier()
    {

        $formulier = '
    <form action="" method="POST">    
        naam <input type="text" name="naam"/><br/>
        email <input type="text" name="email"/><br/>
        website<input type="text" name="website"/><br/>
        reactie <input type="text" name="reactie"/><br/>
        <input type="submit"/>
    </form>'
;

        return $formulier;
    }
}

 
/* Gebruikers gegevens bij het aanroepen opslaan, en via getters op te halen */
class Gebruiker
{
    private $naam;
    private $email;
    private $website;
  
    public function __construct($naam, $email, $website)
    {

        $this->naam = $naam;
        $this->email = $email;
        $this->website = $website;
    }

      
    public function getNaam(){
    
        return $this->naam;
    }

    
    public function getEmail(){
    
        return $this->email;
    }

    
    public function getWebsite(){
    
        return $this->website;
    }
}

 

/* Reactie bij het aanroepen opslaan, en via get ophalen */
class Reactie
{
    private $reactie;
  
    public function __construct($reactie)
    {

        $this->reactie = $reactie;
    }

    
    public function getReactie(){
    
        return $this->reactie;
    }
}

?>


En de index:
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
<?
error_reporting(E_ALL);
require 'gastenboek.class.php';

$db = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$gastenboek = new Gastenboek($db);

if($_SERVER['REQUEST_METHOD'] == 'POST'){

    $gastenboek->reactie_toevoegen(
        new
Gebruiker($_POST['naam'], $_POST['email'], $_POST['website']),
        new
Reactie($_POST['reactie'])
    );
    
}


$reacties = $gastenboek->weergeven();

if(!empty($reacties)){
    
    echo '
<div id="gastenboek">'
;
    
    foreach($reacties as $reactie){
        
        echo '
    <div class="reactie">
        <span class="geplaatst">Geplaatst door: '
. $reactie['naam'] . ' op <strong>' . $reactie['datum'] . '</strong></span>
        <p>'
. $reactie['reactie'] . '</p>
    </div>'
;
    }

    
    echo '
<div>'
;
}
    

echo $gastenboek->getFormulier();
?>
 
PHP hulp

PHP hulp

17/01/2022 02:39:02
 
Dennis Sluijk

Dennis Sluijk

28/02/2012 10:47:58
Quote Anchor link
Is het niet:

(Dit is een indeling van classes hoe je het kan doen)

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
Reactie.Save();

Save() {
 //Execute SQL statements
}

Gebruiker.PostReaction(string message);

PostReaction(string message) {
   $reaction = new reaction();
   $reaction->user = $this;
   $reaction->message = $message;
   $reaction->Save();
}


Zoiets meer OOP of ben ik nou dom bezig?;D

Maar het ziet er goed uit voor je eerste script
Gewijzigd op 28/02/2012 10:51:31 door Dennis Sluijk
 
Wouter J

Wouter J

28/02/2012 11:05:18
Quote Anchor link
De gebruiker is onderdeel van het bericht en niet van het gastenboek. Het bericht is weer een onderdeel van het gastenboek. Eigenlijk zou je dus zoiets moeten maken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php

if($_SERVER['REQUEST_METHOD'] == 'POST'){
  $reactie = new Reaction( $_POST['reactie'], new User($_POST['naam'], $_POST['email'], $_POST['website']) );
  $gastenboek->addReaction($reactie);
}


?>


De Reactie klasse moet je dan wat uitbreiden met een method om de User op te halen (getUser).

Verder ben ik het met wat naamgeving niet eens:
- Gebruik of camelCase of under_score maar niet allebei
- weergeven in het gastenboek zou beter getReactions() moeten heten. Je haalt daar immers de reacties mee op en niet een hele lay-out van een gastenboek.
- Probeer de class-, method- en variabelenamen in het engels te schrijven. Dat is iets internationaler en ook een richtlijn voor elke developer.
- getFormulier hoort naar mijn mening hier niet thuis. Een gastenboek object moet helemaal niks geven over wat er in het formulier zit, sterker nog hij weet niet eens welke velden er allemaal in de Reaction of User klassen zit. Hij weet alleen hoe hij reacties moet opslaan en weer ophalen.
Gewijzigd op 28/02/2012 13:55:23 door Wouter J
 
Gerhard l

gerhard l

28/02/2012 13:50:48
Quote Anchor link
@Dennis zo kan het vast ook, maar zo zie ik niet veel mensen het doen (kan aan mij liggen ;) )

@Wouter je hebt gelijk gebruiker is deel van het bericht. Is het dan netjes/beter om een getUser te maken? Ik heb nu de user toegevoegd bij de class Post (Reactie) en dan via $post->user->getName zijn ze ook bereikbaar.

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
<?
class Post
{
    private $reaction;
  
    public function __construct($reaction, User $user)
    {

        $this->reaction = $reaction;
        $this->user = $user;
    }

    
    public function getReaction(){
    
        return $this->reaction;
    }
}

?>


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?
$query
->execute(array(
    ':name' => $post->user->getName(),
    ':email' => $post->user->getEmail(),
    ':website' => $post->user->getWebsite(),
    ':reaction' => $post->getReaction()
)
        );

?>
Gewijzigd op 28/02/2012 13:51:08 door gerhard l
 
Wouter J

Wouter J

28/02/2012 13:54:54
Quote Anchor link
Je vergeet de user property mee te geven aan de Post 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
<?php
class Post
{
    private $reaction;
    private $user; // deze ben je vergeten
  
    public function __construct($reaction, User $user)
    {

        $this->reaction = $reaction;
        $this->user = $user;
    }

    
    public function getReaction(){
    
        return $this->reaction;
    }
}

?>


Nu ben je verplicht om een getter te maken. Wat ook beter is, anders kan ik zomaar alles wijzigen zonder dat de klasse het door heeft.
 
Gerhard l

gerhard l

28/02/2012 14:09:46
Quote Anchor link
Ja ik zie het, bedankt voor de tip. Alleen doe ik voor mijn gevoel nu wel iets fout omdat ik nu eigenlijk voor naam, email en website 2 getters gebruik, of kan dat wel normaal zijn?

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
<?
class User
{
    private $name;
    private $email;
    private $website;
  
    public function __construct($name, $email, $website)
    {

        $this->name = $name;
        $this->email = $email;
        $this->website = $website;
    }

      
    public function getName(){
    
        return $this->name;
    }

    
    public function getEmail(){
    
        return $this->email;
    }

    
    public function getWebsite(){
    
        return $this->website;
    }
}

 

/* Reactie bij het aanroepen opslaan, en via get ophalen */
class Post
{
    private $reaction;
    private $user;
  
    public function __construct($reaction, User $user)
    {

        $this->reaction = $reaction;
        $this->user = $user;
    }

    
    public function getReaction(){
    
        return $this->reaction;
    }

    
    public function getName(){
        
        return $this->user->getName();
    }

    
    public function getEmail(){
        
        return $this->user->getEmail();
    }

    
    public function getWebsite(){
        
        return $this->user->getWebsite();
    }
}

?>


Aangezien return $this->$user nog steeds private gegevens teruggeeft moet ik ze toch wel apart ophalen?
Gewijzigd op 28/02/2012 14:16:39 door gerhard l
 
Wouter J

Wouter J

28/02/2012 14:20:14
Quote Anchor link
Nee, nu doe je weer iets fout.

In OOP is het vooral het verdelen van taken over verschillende klassen. De Post klasse weet dat hij een user als eigenschap heeft, deze user kan hij opslaan en weergeven, maar hij weet totaal niet wat voor eigenschappen die user heeft. Dus die getName en getEmail en getWebsite methods zijn verkeerd. Dan laat je namelijk zien dat de Post klasse weet wat de User klasse voor eigenschappen heeft.

Je zou de Post klasse dus slechts een getUser method mee moeten geven, deze returned het User object. Vervolgens heb je in de User de get methods voor zijn eigenschappen. Voorbeeldje:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php

foreach( $guestbook->getReactions() as $reaction )
{

  // $reaction is de Post klasse met de getters voor de eigenschappen van Post
  $user = $reaction->getUser(); // $user is nu dus de User klasse met zijn eigen getters

  echo 'Written by <a href="'.$user->getWebsite().'">'.$user->getName().'</a><br>';
  echo '<p>'.$reaction->getContent().'</p>';
}


?>
Gewijzigd op 28/02/2012 14:21:51 door Wouter J
 
Dennis Sluijk

Dennis Sluijk

28/02/2012 14:24:38
Quote Anchor link
Gerhard l op 28/02/2012 13:50:48:
@Dennis zo kan het vast ook, maar zo zie ik niet veel mensen het doen (kan aan mij liggen ;) )


Er is nooit één goede manier. Je moet niet naar andermans scriptjes kijken je moet er zelf logisch over na gaan denken Maar:

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
<?php
 public function reactie_toevoegen(Gebruiker $gebruiker, Reactie $reactie)
    {

        $this->reactie = $reactie;
        $this->gebruiker = $gebruiker;
        
        $query = $this->db->prepare("INSERT INTO bericht (
            naam,
            email,
            website,
            datum,
            reactie
    
        ) VALUES (
            :naam,
            :email,
            :website,
            now(),
            :bericht
        )"
);
        $query->execute(array(
            ':naam' => $gebruiker->getNaam(),
            ':email' => $gebruiker->getEmail(),
            ':website' => $gebruiker->getWebsite(),
            ':bericht' => $reactie->getReactie()
            )
        );

        
        /* Toevoegen aan de bestaande array */
        $array = array(
            'id' => $this->db->lastInsertId(),
            'naam' => $gebruiker->getNaam(),
            'email' => $gebruiker->getEmail(),
            'website' => $gebruiker->getWebsite(),
            'datum' => date('Y-m-d') . ' ' . date('H:i:s'),
            'reactie' => $reactie->getReactie()
        );

        
        $this->reacties[] = $array;
    }

?>


Hiermee sla je het bericht daarom denk van maak een functie Save in je bericht class.

Wat is de bedoeling(nut) van steeds een get functie maken voor elk attribuut in je klasse.

Ik zal het zo doen:

Gastenboek:
- database : Database //gastenboek heeft een database
- posts : array()<Post> //gastenboek heeft een aantal posts
+ GetPosts() return array()<Post> //Om alle berichten van het gestenboek optehalen hij returnt ze en zet ze in het attribute posts

Post:
- message //Een Post heeft een message
- user : User //Een post heeft een user verstuurd
+ Save(Gastenboek $gastenboek) return Boolean //Om het bericht op te slaan je geeft een gastenboek object mee zodat hij weet welke database hij em moet opslaan

User:
- name //spreekt voorzich
- email //spreekt voorzich
- website //spreekt voorzich
Gewijzigd op 28/02/2012 14:45:25 door Dennis Sluijk
 
Gerhard l

gerhard l

28/02/2012 14:50:08
Quote Anchor link
@Dennis omdat je toch alle attributen apart wil kunnen benaderen? En ja de save functie zou ook kunnen, ben eerst nog een beetje aan het experimenteren.

@Wouter ja ik krijg het door, de post kan alleen de user en de reactie van de user ophalen, en de user class kan dan zijn attributen weer ophalen (website,naam,email).
Ik heb het nu zo toegepast, net als jou script alleen dan bij het inserten ipv eruithalen:

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
<?
public function addPost(Post $post)
{

    $this->post = $post;
    $this->user = $this->post->getUser();
        
    $query = $this->db->prepare("INSERT INTO bericht (
        name,
        email,
        website,
        date,
        reaction
            ) VALUES (
        :name,
        :email,
        :website,
        now(),
        :reaction
    )"
);
    $query->execute(array(
        ':name' => $this->user->getName(),
        ':email' => $this->user->getEmail(),
        ':website' => $this->user->getWebsite(),
        ':reaction' => $this->post->getReaction()
        )
    );

    
    /* Toevoegen aan de bestaande array */
    $array = array(
        'id' => $this->db->lastInsertId(),
        'name' => $this->user->getName(),
        'email' => $this->user->getEmail(),
        'website' => $this->user->getWebsite(),
        'date' => date('Y-m-d') . ' ' . date('H:i:s'),
        'reaction' => $this->post->getReaction()
    );

    
    $this->posts[] = $array;
}

?>
 
Dennis Sluijk

Dennis Sluijk

28/02/2012 14:57:17
Quote Anchor link
Gerhard l op 28/02/2012 14:50:08:
@Dennis omdat je toch alle attributen apart wil kunnen benaderen? En ja de save functie zou ook kunnen, ben eerst nog een beetje aan het experimenteren.
Quote:

Waarom maak je ze dan niet public? Want ik zie geen probleem daarin.
Het is volgens mij niet echt het probleem als ze zo:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
$user->name = "Sinterklaas";


bijvoorbeeld de naam definiëren.

Of zie ik dit nou verkeerd?

Naja als je ze wilt afdwingen het via de constructor de definiëren moet je dat vooral doen. Maar ik zie het nut er niet in om dat af te dwingen waarom heb je daarvoor gekozen?
Gewijzigd op 28/02/2012 14:59:23 door Dennis Sluijk
 
Wouter J

Wouter J

28/02/2012 15:00:32
Quote Anchor link
Je weet dat je gewoon variabele kunt gebruiken in functies en niet verplicht $this-> moet gebruiken?
Want regel 4 en 5 zou ik zelf niet doen, misschien als $this->posts een array is zou ik $this->posts[] = $post doen, maar regel 5 zeker niet. Een user is niet een eigenschap van een gastenboek.

Dennis:
Wat is de bedoeling(nut) van steeds een get functie maken voor elk attribuut in je klasse.

Omdat de properties private of protected zijn (public moet je hier nauwelijks voor gebruiken) ben je verplicht een getter te maken.
Als je de properties public maakt kun je ze zomaar aanpassen, zonder dat je het wilt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$dennis
= new User('Dennis', 'http://phphulp.nl', 'dennis@phphulp.nl');
$dennis->name = 'Wouter'; // aah dit wil je toch niet toestaan?
?>

Helaas zijn er in PHP nog geen read-only of write-only methodes voor properties.
 
Dennis Sluijk

Dennis Sluijk

28/02/2012 15:09:16
Quote Anchor link
Quote:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$dennis
= new User('Dennis', 'http://phphulp.nl', 'dennis@phphulp.nl');
$dennis->name = 'Wouter'; // aah dit wil je toch niet toestaan?
?>

Helaas zijn er in PHP nog geen read-only of write-only methodes voor properties.


Ja, inderdaad dat is heel erg jammer.

Ik denk in dit geval alleen maar aan flexibiliteit. Het is gewoon van welk perspectief je het wilt bekijken.

Ik zou het liever dan met __set en __get doen. Om die hele reeks met attributen te verzorgen.
Gewijzigd op 28/02/2012 15:10:04 door Dennis Sluijk
 
Gerhard l

gerhard l

28/02/2012 15:15:41
Quote Anchor link
@Wouter ja variabelen gebruiken is wel wat makkelijker dan hele tijd $this gebruiken ;) En ik wist niet dat je niet perse $this->$var = $var; hoefde te doen, bedankt beide voor de hulp.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?
public function addPost(Post $post)
{

    $user = $post->getUser();
    $query->execute(array(
        ':name' => $user->getName(),
        ':email' => $user->getEmail(),
        ':website' => $user->getWebsite(),
        ':reaction' => $post->getReaction()
    )
);

?>
 
Wouter J

Wouter J

28/02/2012 15:25:37
Quote Anchor link
Dennis:
]Ik zou het liever dan met __set en __get doen. Om die hele reeks met attributen te verzorgen.

Ik gebruik die methods zelf niet heel vaak. Want een object kan ook properties hebben die je niet mag lezen, of niet mag schrijven en als je dat wilt controleren heb je vaak een slechtere flexibiliteit dan dat je aparte getters/setters maakt.

@Gerhard, niks te danken. Leuk dat jij, en veel mensen hier op het forum, zich gaan verdiepen in OO!
 
Dennis Sluijk

Dennis Sluijk

28/02/2012 15:35:41
Quote Anchor link
In de getter / setter kan je makkelijk regelen dat je de ene attribuut wel terug geef / zet.
 
Kris Peeters

Kris Peeters

28/02/2012 17:44:05
Quote Anchor link
(Zie het volgende los van dit specifiek geval; jullie zijn goed bezig; doe vooral zo voort)

Een verdere mogelijkheid:

Zet alle eigenschappen op private.
Buiten de class blijf je van de eigenschappen af; je communiceert enkel via functies.
Op die manier heb je altijd een controle, zowel op get als op set.

Dan kan je ook functies hebben die zowel getter als setter zijn.
Meerdere systemen doen dit in meerdere talen (denk bv. aan jQuery)

Het principe is: wanneer je een parameter meegeeft, wordt de functie gezien als setter, als je de parameter leeg laat, is het een getter.

Dus ...
niet meer
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
$user
->username = "John";
...

echo $user->username;
...

$user->setUsername("John");
?>


maar
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
// als setter
$user->username("John");
//als getter
echo $user->username();
?>


Dan kan je de getter/setter-functie de eenvoudige naam geven, en moet je de eigenschappen maar wat hernoemen.
 
Wouter J

Wouter J

28/02/2012 17:50:28
Quote Anchor link
@Kris, de jQuery manier dus. Lijkt mezelf niet het meest OO achtig.. Je hebt geen idee of je nou aan het setten of getten bent en de functie moet allebei kunnen. Tenzij je natuurlijk zoiets doet:
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
<?php

class Example
{
  protected $name;

  public function setName( $name )
  {

    $this->name = ucfirst((string) $name);
  }

  public function getName()
  {

    return $this->name;
  }


  public function name()
  {

    if( func_num_args() == 1 )
      $this->setName( reset(func_get_args()) );
    else
      return $this->getName();
  }
}
 
Kris Peeters

Kris Peeters

28/02/2012 17:51:40
Quote Anchor link
Eventueel zo, ja
 



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.