OOP leren

Overzicht Reageren

Pagina: 1 2 3 4 volgende »

Roeltje M

Roeltje M

20/07/2009 22:03:00
Quote
Hoi,

Ik probeer nu OOP te leren door zelf klein te beginnen en steeds uit te bouwen. Nu heb ik het volgende:

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

class person
{
    public $name;
    public $age;
    private $pincode;
    
    function
__construct($personName,$personAge)
    {

        $this->name = $personName;
        $this->age = $personAge;        
    }

    
    // NAME SETTER & GETTER
    public function set_name($newPersonName)
    {

        if(empty($this->name))
        {

            $this->name = $newPersonName;
        }

        else
        {
            // ERROR
        }
    }

    
    public function get_name()
    {

        return $this->name;
    }

    
    // AGE SETTER & GETTER    
    public function set_age($newPersonAge)
    {

        if(empty($this->name))
        {

            $this->age = $newPersonAge;
        }

        else
        {
            // ERROR
        }
    }
    
    
    public function get_age()
    {

        return $this->age;
    }
}


?>


Hier heb ik echter een paar vragen over:

a. Zit ik op het goede spoor met OOP?
b. Hoe moet ik errors maken met OOP?
c. Moet property pincode ook in de constructor?
d. Wat is beter, variabelen BUITEN de echo halen of gewoon erin laten staan (omdat het ook werkt en het onnodig tijd kost? (voorbeeld:)
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php

echo "De naam van $roel->name is ".$roel->name;
// De naam van Roel Moser is Roel Moser
?>
Gewijzigd op 01/01/1970 01:00:00 door Roeltje M
 
PHP hulp

PHP hulp

03/09/2010 01:27:26
Gesponsorde koppelingen:
 
Jelmer rrrr

Jelmer rrrr

20/07/2009 22:36:00
Quote
Hier heb je nu een class met z'n properties, en dat is op zich goed.

Je hebt de members $name en $age public gemaakt. Dat betekent dat je ze ook via $roel->age = 'gisteren' kan aanpassen, terwijl je juist die setters hebt gemaakt om controle te hebben over welke waarden $roel->age kan aannemen. $age en $name moeten private worden (of protected, maar ik zou gaan voor private zodat je altijd, ook in extend classes via de getters & setters bij die variabelen moet komen, zodat je altijd langs de controle moet)

Je kan er voor kiezen om ook je constructor gebruik te laten maken van de setters. Nu is de invoer ongecontroleerd, en kan je nog niet zeggen dat de waarde die in $age zit ook daadwerkelijk een nummertje is.

Foutafhandeling kan je heel gemakkelijk doen via exceptions. Alles wat mis kan gaan binnen een functie, en wat niet "verwacht gedrag" is, kan je gemakkelijk bekend maken via exceptions. Voorbeeldje:
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
<?php
class Person {

    private $_name;

    public function set_name($name)
    {

        if(mb_strlen($name) < 3)
            throw new Exception('Naam moet ten minste 3 karakters lang zijn');

        if(strpos($name, '@') !== false)
            throw new Exception('Wie heeft er nou een apenstaart in zijn naam!?');

        $this->_name = $name;
    }
}

?>

Het voordeel van exceptions is dat je niet bij iedere aanroep naar een functie hoeft te controleren of er niet een fout is opgetreden. Je laat de exception die dan via throw gegooid wordt gewoon vallen tot op het niveau in je code waar je er iets aan kunt 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
15
<?php
try {
    if(form_is_submitted())
    {

        $x = new Person();
        $x->set_name($_POST['name']);
        $x->set_age($_POST['age']);
        display_person($x);
    }
}
catch(Exception $e) {
    display_error($e->getMessage());
}


display_form();
?>

Ander leuk iets is dat je verschillende soorten exceptions op andere niveaus kan opvangen. Bijvoorbeeld, PDOException erft van Exception, InvalidArgumentException erft van Exception, en MijnEigenException erft van Exception:
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 MijnEigenException extends Exception {

}


try {
    doe_iets_met_database($_POST['argument']);

    echo 'WIN!';
}
catch(MijnEigenException $e) {
    echo 'programmeerfout:' . $e->getMessage();
}
catch(PDOException $e) {
    connect_to_backup_database();
    try_again();
}
catch(Exception $e) {
    echo 'Help!?: ' . $e->getMessage();
}

?>


Aan je constructor geef je eigenlijk alleen de data mee die het object altijd nodig heeft, en waar hij direct van afhankelijk is. Heb je bijvoorbeeld een Person_Store, een class die Person-instanties in de database kan zetten, en ze eruit kan toveren, en die Person_Store verwacht een PDO verbinding:
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
<?php

class Person_Store {

    protected $_pdo;

    public function __construct(PDO $pdo)
    {

        $this->_pdo = $pdo;
    }

}


$pdo = new PDO('...');
$store = new Person_Store($pdo);
?>

PDO accepteert zo ook 3 argumenten voor de constructor (verbinding-uri, gebruikersnaam en wachtwoord, waarbij de laatste twee optioneel zijn) Zonder die gegevens is het object nutteloos, het object is er direct van afhankelijk.

Je mag van mij helemaal zelf weten of je je variabelen binnen of buiten quotes houdt. Besef je echter wel dat je niet veel met $this->name zal doen, maar eerder met $this->name(), de getter-method. Ook geen probleem, dit zal wel werken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
echo "De naam van \$roel is {$roel->name()} en hij is {$roel->age()} jaar oud";
?>

Maar wat nu als $roel->name() "<script>evil()</script>" teruggeeft, dan ben je nu de pineut. Daarom raad ik je voor dit soort data, welke indirect van de gebruiker afkomstig is, altijd buiten quotes te houden zodat je jezelf eraan kan herinneren dat je nog even moet denken aan htmlspecialchars of htmlentities. Je kan ook sprintf gebruiken om het overzichtelijker te houden (plus beetje veiligheid doordat %d het tweede argument als een int cast, en <script>evil()</script> dan dus 0 wordt):
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$x
= sprintf('De naam van $roel is %s en hij is %d jaar oud',
    html($roel->name()),
    $roel->age());
?>

Je zou ook een functie a la sprintf kunnen maken die strings alvast voor je door htmlspecialchars trekt. Dan heb je bijna geen extra typwerk meer.
 
Emmanuel Delay

Emmanuel Delay

20/07/2009 22:45:00
Quote
Variabelen altijd uit de quotes halen.
Bij een echo gebruik je meestal best enkele quotes ( ' ).

Verder snap ik dit niet: if(empty($this->name)) $this->name = $newPersonName;
Het is niet gebruikelijk dat je een eigenschap niet mag overschrijven.
 
Roeltje M

Roeltje M

20/07/2009 23:14:00
Quote
@ Jelmer,

Bedankt voor de info!

Toch heb ik nog een paar vraagjes:

a. Is mb_strlen gelijk aan strlen?
b. wat is het verschil tussen $roel->name en $roel->name()? Waarom zal ik de laatste vaker gebruiken?
c. je gebruikte op gegeven moment
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<? display_person($x); ?>
Dit is een fictieve functie toch (in iedergeval nog niet in mijn scriptje). Dit geeft alle gegevens weer van person?
d. Moet $pincode wel of niet in de constructor? Niet toch?
e. Heb je een voorbeeld van een property dat public kan zijn? Op zich kan toch alles met setters?
f. Als ik het goed heb zit de structuur van Exeptions zo?
Exeptions
- PDOException
- InvalidArgumentExeptions
- ...
Moet ik zelf ook Exeptions maken, of hoeft dat niet perse?


g. Is iets als
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
<?         if(mb_strlen($name) < 3)
            throw new Exception('Naam moet ten minste 3 karakters lang zijn'); ?>
valid PHP? Moet het niet
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?
        if(mb_strlen($name) < 3) {
            throw new Exception('Naam moet ten minste 3 karakters lang zijn'); } ?>
zijn?

h. Ik moet dus altijd controleren of er geen html spul in de input zit dmv htmlspecialchars (of entities). Dit hoeft toch niet als ik de Input zelf in handen heb? Of gewoon ALTIJD inbouwen (lees: aanleren)?
Gewijzigd op 01/01/1970 01:00:00 door Roeltje M
 
Jelmer rrrr

Jelmer rrrr

20/07/2009 23:47:00
Quote
a. mb_strlen is de multi-byte versie van strlen. ß is bij mij volgen strlen() bijvoorbeeld 2 karakters lang vanwege utf-8. mb_strlen kan daar beter mee overweg. Maar dat is een detail, en heeft niet veel met OOP te maken :)

b. $roel->name is een verwijzing naar de member-variabele de class waarvan een instantie zit in $roel. $roel->name zal een foutmelding opleveren wanneer je $name een private of protected member maakt. $roel->name() roept die name-method (de "getter") aan. Getters en setters zijn maar naampjes, het zijn het gewoon methods uiteindelijk.

c. Ik gebruikte gewoon even fictieve functies om te laten zien wat je op dat soort plekken in je code zou kunnen doen. Veel functies gebruiken in plaats van overal plat de code neerzetten is sowieso wel prettig om je code begrijpbaar en hapbaar te houden.

d. Is $pincode noodzakelijk bij het aanmaken van het object? Kan je object bestaan zonder dat z'n pincode-member een waarde heeft? Heeft je object een standaard-waarde voor pincode?

e. In de praktijk kan je public gebruiken wanneer je geen "zin" hebt om een getter & setter te schrijven, maar dat is best een slechte gewoonte. Ik ken geen theoretisch gezien goed gebruik van public voor member-variabelen in PHP, omdat PHP geen dingen kent als read-only en het afdwingen van types voor variabelen. (waardoor je effectief niet weet wat er in een variabele zit zonder te controleren)

f. De standaard-Exception class is Exception. Alleen instanties van Exception kan je gebruiken in combinatie met throw. (throw new stdClass() werkt niet) Je kan je eigen exceptions maken door Exception te extenden (want een MijnSpecialeException is ook een Exception, want het erft alle eigenschappen van Exception over) Eigen exceptions kan je bijvoorbeeld gebruiken om het soort aan te duiden (valende setters, maar daar kan je ook de standaard InvalidArgumentException meestal wel voor gebruiken) of om je eigen details aan de exception toe te voegen. PDOException bevat bijvoorbeeld de extra member $errorInfo, waarin extra informatie van de database(driver) over de fout staat. Zou je zelf een HTTP-Request class maken (een class die webpagina's kan opvragen o.i.d.) dan zou je een HTTPRequestException kunnen maken die details over de fout bevat (de http-headers die de server terugstuurde bijv.)

g. Je mag bij if-else statements de accrolades weglaten, maar dan wordt alleen de eerst volgende opdracht als de opdracht beschouwd die normaal binnen de accolades staat. Bijv: if(is_valid()) echo 'a'; echo 'b'; Nu zal alleen de eerste echo afhankelijk zijn van is_valid(), de tweede echo wordt altijd uitgevoerd. Dat is ook de reden dat je voorzichtig moet zijn met het weglaten van accolades, je code kan er bestwel onleesbaar door worden.

h. Alle invoer die niet hard-coded in je PHP staat is potentieel gevaarlijk. Ooit was er een idee om PHP te voorzien van 'tainted variabelen'. De variabelen houden dan bij hoe gevaarlijk ze zijn. Zo kreeg je een foutmelding wanneer je mysql_query('SELECT * FORM tabel WHERE x = ' . $_POST['varname']) deed, omdat $_POST['varname'] van buiten kwam, en gemene quotes zou kunnen bevatten die je query manipuleren. Pas wanneer je $_POST['varname'] eerst door mysql_real_escape_string haalde werd het resultaat daarvan gemarkeerd als veilig-voor-sql-code. Hetzelfde geldt voor HTML. echo $_POST['data'] kan gevaarlijk zijn, als $_POST['data'] HTML bevat. Bijvoorbeeld een meta-redirect tag naar een foute site, of Javascript die je cookies steelt. Daarom is het heel belangrijk om iedere keer als je een variabele echo't, na te gaan waar alle data in die variabele vandaan komt, en welke inhoud er in theorie allemaal in zou kunnen zitten. Eigenlijk hoop ik dat ze die tainted variabelen ooit nog op een of andere manier in PHP stoppen, al dan niet uitschakelbaar, maar het zou enorm helpen met het vinden van veiligheidslekken. Tot dan kan je of heel goed zelf die taints bijhouden (is te doen, maar je moet wat oefenen) of je kan veilig spelen en htmlentities op alle variabelen gebruiken.

Op PHPhulp staan wel een aantal tutorials over XSS, en hoe je je er tegen kan wapenen. Op PHP.net is het proposal voor tainted variabelen te vinden. Voor jouw interessant is vooral hoe de taints door kunnen sijpelen in andere variabelen (immers 'abc' . $_POSt['xxx'] is net zo onveilig als $_POST['xxx']). sprintf is ook wel handig hiervoor (maar ook voor veel andere dingen) omdat je op die manier alvast kunt vaststellen van wat voor type je in je uitvoer verwacht, en je ook zeker bent dat je dat type tekst in je uitvoer zal krijgen. (bijv. %d garandeert een nummer, evil-javascript-html is dan dus uitgesloten)
 
Erik Rijk
Moderator

Erik Rijk

21/07/2009 09:39:00
Quote
Jelmer,

Ik ben af en toe zo blij dat jij van typen houd :)
Hier heb ik ook weer wat van geleerd!, thnx.
 
Roeltje M

Roeltje M

21/07/2009 10:38:00
Quote
Ik leer echt veel van je Jelmer! Bedankt!

Dus ipv $roel->name moet ik eigenlijk $roel->get_name() gebruiken? Dus wat ik eerst deed was direct de property aanroepen (had ik zelf niet door :D)?

Ik zal eens wat verder knutselen, en dan kom ik op dit topic terug :). Verder zal ik eens PDO gaan proberen.
 
Erik Rijk
Moderator

Erik Rijk

21/07/2009 10:56:00
Quote
Je roept een functie aan, en dat doe je altijd dmv: $this->function()... waar je verder nog attributen aan mee kan geven indien gewenst.
 
Tikkes Unknown

Tikkes Unknown

21/07/2009 11:00:00
Quote
zalige post jelmer...jij zou boeken moeten schrijven :-) ik zou er zeker kopen...hier leer ik meer van dan ik op school doe
 
Roeltje M

Roeltje M

21/07/2009 11:38:00
Quote
@ Tikkes: Ik leer hier ook meer dan op school :D.

Ik ben weer een stukje verder:

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

class person
{
    private $_name;
    private $_age;
    private $_password;
    
    function
__construct($personName,$personAge)
    {

        $this->_name = $personName;
        $this->_age = $personAge;        
    }

    
    // NAME SETTER & GETTER
    public function set_name($newPersonName)
    {

        if(!preg_match('{^[a-z][a-z0-9\-_]{2,}$}i', $newPersonName))
        {

            throw new InvalidArgumentException('Ongeldige naam');    
        }

        if(mb_strlen($newPersonName) < 3)
        {

            throw new InvalidArgumentException('Naam moet minstens 3 karakters lang zijn');
        }


        $this->_name = $newPersonName;    
    }

    
    public function get_name()
    {

        return $this->_name;
    }

    
    // AGE SETTER & GETTER    
    public function set_age($newPersonAge)
    {

            $this->_age = $newPersonAge;
    }
    
    
    public function set_password($password)
    {

        if(mb_strlen($password) < 3)
        {

            throw new InvalidArgumentException('Wachtwoord is te kort');
        }

        $this->_password = md5($password);
    }


    public function get_password()
    {

        return $this->_password;
    }

    
    public function get_age()
    {

        return $this->_age;
    }

    
    public function display_person()
    {

        return $this->_name;
        return $this->_age;
    }

    
    public function as_array()
    {

        return array(
            'name' => $this->_name,
            'age' => $this->_age,
            'password' => $this->_password
            );
    }    

}
    function
form_is_submitted()
    {

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

            return true;
        }

        else
        {
            return false;
        }
    }

?>
Index.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
<form name='OOP' method="post">
    <input type='password' name="pass" /> <input type='submit' name='btn_OOP' value='Set Pass' />
</form>
<?php
$roel
= new person('Roel Moser',17);
if(form_is_submitted())
{

    try
    {
        $roel->set_password($_POST['pass']);
    }

    catch (InvalidArgumentException $e)
    {

        echo $e->getMessage();
    }
}


echo 'Mijn naam is '.$roel->get_name().', '.$roel->get_age().' jaar oud.<br /><br />';

$array = $roel->as_array();

foreach($array as $prop => $val)
{

    echo $prop . ' = ' . $val . '<br />';
}

?>


Ook hier heb ik weer een paar vraagjes:

a. zijn de functions display_person() en as_array() goed?
b. De function form_is_submitted moet neem ik aan buiten de Classes. Is deze functie goed?
c. Moet ik als ik een class User_store maak (voor database), ook een __construct method hebben?
d. is het handiger om mysql_real_escape_string etc in de function zelf te zetten, of al bij de input toe te passen?
Gewijzigd op 01/01/1970 01:00:00 door Roeltje M
 
Jelmer rrrr

Jelmer rrrr

21/07/2009 21:32:00
Quote
a. Jouw implementatie van display_person gaat niet werken. Je probeert de functie 2 antwoorden te laten geven (na elkaar) maar bij het eerste return-statement dat je binnen de functie tegenkomt zal je functie stoppen, en zal de 'uitvoer' van die functie dat zijn wat je op dat moment returnt.

Verder hoeft je Person-class op zich niet zo'n method te hebben. Je kan denk ik beter de Person-class verantwoordelijk houden voor de werkelijke data van de persoon, en een andere class of functie verantwoordelijk maken voor het correct weergeven (omzetten naar HTML, of XML, of een plaatje) van je Person-objecten. Eigenlijk is het over het algemeen een goed plan om je classes en je functies zo min mogelijk zelf te laten doen, en zoveel mogelijk te laten uitbesteden aan andere functies en classes. Daardoor komt er in je code eigenlijk allemaal goed-leesbare pseudo-code te staan (gewoon functienamen die beweren dat ze iets doen, geen daadwerkelijke code die allemaal ingewikkelde statements bevat), en kan je je beter focussen op één ding tegelijk.

b. form_is_submitted is niet specifiek voor de Person-class, maar is meer een hulp-functie. Of eigenlijk is het meer zo'n functie als ik hierboven beschreef. Het is maar een functie om één simpel statement heen, maar je code is erdoor veel simpeler te lezen voor mensen die geen PHP kennen (en dus niet bekend zijn met $_SERVER) of voor later, wanneer er alweer een betere manier is om dat te doen. Hij kan trouwens korter als je dat zou willen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
function is_form_submitted()
{

    return $_SERVER['REQUEST_METHOD'] == 'POST';
}

?>


c. Als je User_Store class ergens van afhankelijk is (bijvoorbeeld een $link_identifier die mysql_connect teruggeeft, of een instantie van PDO) dan zou je die via de constructor mee kunnen geven. Als hij nergens van afhankelijk is, dan mag je de constructor leeg laten. Je kan de constructor ook gebruiken om wat initialisatie-werk te doen. In een heeeeeel slecht voorbeeld zou je in de constructor kunnen controleren of de tabel wel bestaat, en zo niet deze aanmaken. (Maar dat doe je natuurlijk niet, omdat die extra query in de praktijk volledig overbodig is, omdat de tabel toch altijd wel bestaat, en je het anders zelf handmatig makkelijker kan oplossen :) )

d. Ik zou het veilig maken van je data voor queries of html zo dicht mogelijk bij de plek waar je de waarden ook daadwerkelijk in de query gaat gebruiken of in de html gaat printen zetten. Stel dat je bijvoorbeeld standaard htmlentities over je invoer haalt, maar je beslist toch $_POST['xxx'] in imagettftext te willen gebruiken, dan moet je eerst die entities weer terugdraaien. Als je je data altijd zo rauw en puur mogelijk houdt, dan kan je die op het moment dat hij veilig moet zijn voorzien van de juiste filters, en alleen de juiste filters (dat zijn filters die geen sporen nalaten, vergelijk het resultaat van addslashes met mysql_real_escape_string) alvorens je de data op die plek gebruikt. En omdat de functie die bijvoorbeeld de query opbouwt het beste weet wat veilig is voor die query (alles wat door mysql_real_escape_string is gekomen) en wat niet, is het goed om inderdaad binnen die functie de filters er overheen te halen.
 
Roeltje M

Roeltje M

21/07/2009 21:41:00
Quote
Bedankt weer Jelmer! Punt B. en D. snap ik, A. voor een deel, C. niet (heb geen ervaring met PDO, dus weet niet waar user_store afhankelijk van kan zijn etc.)

Over punt A. Het zou het best zijn als ik dus een aparte Class maak waar ik ALLE gegevens uit kan oproepen? Hoe ziet bijvoorbeeld de functie die bij mij display_person() heet eruit als ie goed is?
 
Jelmer rrrr

Jelmer rrrr

21/07/2009 22:18:00
Quote
Er moet uiteindelijk een plek zijn in je code waar je de gegevens uit de database omzet in een leuke webpagina, ik denk dat dat pad van gegevens er zeg maar zo ongeveer uit zou zien:
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
<?php
$db
= mysql_connect('...');
mysql_select_db('imdb', $db);

$person_store = new Person_Store($db);

$person = $person_store->get($_GET['person_id']);
// Person_Store voert een query uit, en maakt met de array die hij terug krijgt
// van de database een nieuw Person object aan, en vult de properties van dat
// object met de data uit die array. Vervolgens geeft hij dat object terug via
// return, en zit er dus een instantie van Person in $person.


echo '<h1>' . htmlentities($person->name()) . '</h1>';

echo '<p>Het is algemeen bekend dat hij ' . $person->age() . ' jaar oud is</p>';
?>

Die laatste twee regeltjes zouden de display_person functie kunnen 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
<?php
function display_person(Person $person)
{

    echo '<h1>' . htmlentities($person->name()) . '</h1>';

    echo '<p>Het is algemeen bekend dat hij ' . $person->age() . ' jaar oud is</p>';
}


/* ... */

$person = $person_store->get($_GET['person_id']);

display_person($person);
?>

Je zou ook in plaats van een functie een nieuwe class kunnen gebruiken, bijvoorbeeld de class Website, welke diezelfde functie als method kent (maar dan er een mooie layout omheen tekent) Wat ik vooral in het voorbeeld wou laten zien is dat het totaal niet uitmaakt welke persoon er in $person zit, zolang je weet dat $person de methods die de class Person heeft ook heeft, weet je hoe je hem moet gebruiken, en kan je binnen de functie display_person veilig $person->name() en $person->age() aanroepen.
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
<?php
$cast
= array(
    'harry' => new Person(...),
    'hermione' => new Person(...),
    'ron' => new Person(...)
);


foreach($cast as $character => $actor)
{

    echo $character . ' werd gespeeld door ';
    display_person($actor);
}


?>


Merk ook even op hoe ik m'n $person_store vul. Ik geef hem de link-identifier mee (zie de handleiding van mysql_connect) zodat hij deze heeft wanneer hij intern mysql_query aanroept (welke de link-identifier als tweede argument slikt) Nu is bij mysql de link-identifier optioneel, en alleen nodig wanneer je meerdere verbindingen met verschillende databases gebruikt, en daarom gebruikte ik in m'n voorbeeld PDO, omdat je wanneer je PDO gebruikt altijd je instantie van PDO erbij moet hebben (omdat PDO een class is, maar in weze is het hetzelfde als bij mysql_connect, de instantie van PDO bevat de informatie over welke database je moet aanspreken) Dus omdat m'n Person_Store object zonder die link-identifier niet weet met welke database hij moet praten, en daardoor compleet clueless en onbruikbaar is, mag je zeggen dat hij nogal afhankelijk is van die link-identifier, en dat je die al bij de constructor mag meegeven.

Je ziet het meegeven van dit soort 'objecten' aan de constructor (okee, link-identifier is niet een object, maar PDO wel) wel vaker, omdat het eigenlijk de beste* manier is om je classes die toch afhankelijk zijn van andere classes in hun behoeften te voorzien.

* vind ik :) Er zijn mensen die liever een registery of singleton gebruiken, maar dan raak je eigenlijk een deel van de kracht van object georiënteerd programmeren kwijt. Maar dat is een ander verhaal.
Gewijzigd op 01/01/1970 01:00:00 door Jelmer rrrr
 
Roeltje M

Roeltje M

20/08/2009 10:15:00
Quote
Ben nu weer begonnen met OOP. Dit is wat ik op het moment heb. Ik heb alleen het gevoel dat mijn construct niet goed is. En als ik een functie login() wil maken, moet ie dan in de class users? Ik moet uiteindelijk ook nog PDO in gaan bouwen. Dit is mijn code
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
<?php

class User
{
    private $_id;
    private $_username;
    private $_pass;
    private $_naam;
    private $_adres;
    
    function
__construct($inputId,$inputUsername,$inputPassword,$inputNaam,$inputAdres)
    {

        $this->_id = $inputId;
        $this->_username = $inputUsername;
        $this->_pass = $inputPassword;
        $this->_naam = $inputNaam;
        $this->_adres = $inputAdres;                        
    }



    // GETTERS & SETTERS
    
    public function getId()
    {

        return $this->_id;
    }

    
    public function getUsername()
    {

        return $this->_username;
    }

    
    public function setUsername($username)
    {

        if(!preg_match('{^[a-z][a-z0-9\-_]{2,}$}i', $username))
            throw new InvalidArgumentException('Ongeldige username');
        
        $this->_username = $username;    
    }

    
    public function getNaam()
    {

        return $this->_naam;
    }

    
    public function setNaam($naam)
    {

        if(!preg_match('{^[a-z][a-z0-9\-_]{2,}$}i', $naam))
            throw new InvalidArgumentException('Ongeldige naam');
        
        $this->_naam = $naam;    
    }
    
    
    public function getAdres()
    {

        return $this->_adres;
    }

    
    public function setAdres($adres)
    {

        if(strlen($adres) < 6)
            throw new InvalidArgumentException('Ongeldig adres');
        
        $this->_adres = $adres;    
    }        



}[
/code]

OM de 1 of andere reden krijg ik ook deze error:


Parse error: syntax error, unexpected T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or '}' in /home/vhosts/design-xtr.nl/httpdocs/sites/Houtenladen/oop.php on line 5
Gewijzigd op 01/01/1970 01:00:00 door Roeltje M
 
Jelmer rrrr

Jelmer rrrr

20/08/2009 10:32:00
Quote
Dat ligt niet aan dat stukje code, dat stukje code werkt hier perfect (klein detail, je kan nog wel even public voor function __construct zetten.)

Ik zou het inloggen niet in de class User zelf opnemen. Bij de login-procedure is het user-object het subject, het object dat het ondergaat (dat slachtoffer is, het krijgt meerwaarde)

Ik zou een aparte class maken welke je login-sessie beheert, UserSession o.i.d. Je zou daarin het inloggen kunnen regelen, en vanuit daar kan je dan bijvoorbeeld via de method $usersession->user() een instantie van deze User class krijgen voor de op dat moment ingelogde user. User is dan dus meer een resultaat van het inloggen dan diegene die voor het inloggen verantwoordelijk is.

edit: of gebruik je nog PHP 4? Dan zou het kunnen dat die bovenstaande code niet werkt. PHP 4 kent onder andere geen public/private/protected, geen __construct, en nog een heleboel ellende met references naar instanties. Wil je OOP leren? Dan kan je niet zonder PHP 5 (in 4 is het ingewikkelder om te leren zelfs!)
Gewijzigd op 01/01/1970 01:00:00 door Jelmer rrrr
 
Roeltje M

Roeltje M

20/08/2009 10:48:00
Quote
Mijn __construct is verder dus wel goed? Want ik heb zeg maar in database een tabel met veel gegevens, zoals adres, postcode etc. Moeten deze allemaal in construct?

Ga ik nu maar is proberen om login etc te maken.

edit:
Heb server geupgrade naar PHP 5+



-- EDIT --

Ik heb nu dit voor het inloggen:
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
<?
class UserSessions
{
    try
    {
        $db = new PDO('mysql:host=localhost;dbname=users','user','password');
    }

    catch(PDOException $e)
    {

        echo $e->getMessage();
    }

    
    public function login($inputUser,$inputPass)
    {

        $sql = "SELECT
                    id, username, password
                FROM
                    users
                WHERE
                    username = :username
                AND
                    password = :password"
;
        $stmt = $db-prepare($sql);
        
        $stmt->bindParam(':username', $inputUser);
        $stmt->bindParam(':password', $inputPass);
        
        $stmt->execute();
        
        $aantal = $db->query($sql)->fetch(PDO::FETCH_ASSOC);
        if($aantal = 1)
        {

            while($row = $stmt->fetch(PDO::FETCH_ASSOC))
            {

                $_SESSION['id'] = $row['id'];
                $_SESSION['user'] = $row['username'];
            }
        }

        else
        {
            throw new PDOException('Onjuiste inloggegevens.');        
        }
    }
}

?>


Goed of niet goed? That's the question.
Gewijzigd op 01/01/1970 01:00:00 door Roeltje M
 
Roeltje M

Roeltje M

21/08/2009 23:19:00
Quote
iemand?
 
Afra ca

Afra ca

22/08/2009 09:41:00
Quote
Regel 23 een typefoutje ;)

$stmt = $db-prepare($sql);

wordt

$stmt = $db->prepare($sql);

En bij je fetchen voer je nog een keer je query uit..... Aangezien je hem al met execute hebt uitgevoerd.....

Dus

$aantal = $db->query($sql)->fetch(PDO::FETCH_ASSOC);

wordt

$aantal = $stmt->fetch(PDO::FETCH_ASSOC);

En je laatste exception vang je niet af.
 
Jelmer rrrr

Jelmer rrrr

22/08/2009 10:38:00
Quote
Ik zou sowieso geen PDOException gooien. PDOExceptions worden normaal alleen gegooid wanneer er een fout is met de database (fout in query, fout met verbinding). Als je nu ook een PDOException gaat gooien voor fout met wachtwoord, dan heeft PDOException geen speciale betekenis meer. Je kan beter een eigen exception maken en die gooien:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php

class UserSessionException extends Exception { }

throw new UserSessionException('Combinatie van gebruikersnaam & wachtwoord niet bekend');

?>


Trouwens, is dit voor even, of sla je geen sha1-hash van je wachtwoord op? Alleen een hash opslaan is veiliger, want dan kan niet iemand je wachtwoord zomaar ontfutselen wanneer hij via sql-injection o.i.d. de verkeerde data uit de database weet te vissen. Je gebruikt wachtwoord uit je database niet verder in je code, dus je hoeft hem ook niet in het SELECT deel van je query te vermelden :)

Vang exceptions pas af wanneer je een alternatief hebt. Als je UserSessions class geen verbinding kan maken, dan is dat niet een probleem dat UserSessions kan oplossen. Laat die exception dan gewoon vallen, en vang hem op daar waar je bijvoorbeeld een fout-pagina kan weergeven.

Sowieso kan je geen try/catch blokken of zelfs constructors aanroepen bij het definiëren van de class. Die code moet dan in de constructor. En je moet je $db dan even een (protected?) membervariabele van je class maken, en hem aanspreken via $this->db.

Verder, als je PDO gebruikt, is deze ook erg nuttig (direct aanroepen nadat je je PDO object hebt aangemaakt)
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$db
->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
?>


En als laatste: UserSessions? Het is op zich logischer om een class naar een zelfstandig naamwoord enkelvoud te vernoemen. Immers, je maakt instanties aan van die class, en die instanties zijn dan zeg maar de individuen.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$x
= new Persons();

$y = new UserSessions();
?>

$x is niet meerdere personen, net zoals $y niet meerdere sessies tegelijkertijd kan zijn. Ik zou je class UserSessionController of UserSessionProvider o.i.d. noemen, want dat is het. Het is een class die iemand in staat stelt in te loggen en een sessie te starten.
 
Roeltje M

Roeltje M

22/08/2009 11:17:00
Quote
Ik heb nu dit dus:

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

class UserSessionController
{
    try
    {
        $db = new PDO('mysql:host=localhost;dbname=users','user','password');
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }

    catch(PDOException $e)
    {

        echo $e->getMessage();
    }

    
    public function login($inputUser,$inputPass)
    {

        $sql = "SELECT
                    id, username
                FROM
                    users
                WHERE
                    username = :username
                AND
                    password = MD5(:password)"
;
        $stmt = $db->prepare($sql);
        
        $stmt->bindParam(':username', $inputUser);
        $stmt->bindParam(':password', $inputPass);
        
        $stmt->execute();
        
        $aantal = $stmt->fetch(PDO::FETCH_ASSOC);
        if($aantal = 1)
        {

            while($row = $stmt->fetch(PDO::FETCH_ASSOC))
            {

                $_SESSION['id'] = $row['id'];
                $_SESSION['user'] = $row['username'];
            }
        }

        else
        {
            throw new PDOException('Onjuiste inloggegevens.');        
        }
    }
}

?>


Ik gebruik md5 ipv sha1. En mijn PDO is verder goed zo? Dit is eerste keer dat ik PDO gebruik.

Verder gebruik ik dit stuk niet:

stukje:
Vang exceptions pas af wanneer je een alternatief hebt. Als je UserSessions class geen verbinding kan maken, dan is dat niet een probleem dat UserSessions kan oplossen. Laat die exception dan gewoon vallen, en vang hem op daar waar je bijvoorbeeld een fout-pagina kan weergeven.

-- en --

En je moet je $db dan even een (protected?) membervariabele van je class maken, en hem aanspreken via $this->db.
 
Ivo K

Ivo K

22/08/2009 11:27:00
Quote
Ik zou oppassen met het gebruik vand md5, er zijn op internet al veel scripts die het kunnen "kraken" al vermoed ik gewoon dat het eens script is wat in een grote database kijkt, maar als een hacker md5 wil kraken is hij veel sneller klaar met sha1 () of hash ( 'sha256' , $text ) .
 

Pagina: 1 2 3 4 volgende »



Overzicht Reageren