OOP Beginnershandleiding (PHP5)
Door Joren de Wit, 18 jaar geleden, 195.319x bekeken
Een inleiding tot het object geörienteerd programmeren in PHP5
Gesponsorde koppelingen
Inhoudsopgave
- Inleiding
- Object geörienteerd denken
- Foute denkwijze
- Object georiënteerd programmeren
- Visibility
- Naamgeving
- Constructor __construct()
- Voorbeeld: HTML tabel
- Inheritance
- Static methods en properties
- Abstract classes en Interfaces
- Slotwoord en referenties
Er zijn 49 reacties op 'Oop beginnershandleiding php5'
Gesponsorde koppelingen
Hele goede tutorial voor beginners, heel duidelijk vooral. Niet dat ik het nodig heb, maar toch. :-)
2 kleine puntjes:
1) Je gebruikt *soms* Nederlandse en Engelse namen door elkaar heen. Dat leest niet erg prettig.
2)
Dat is natuurlijk niet waar, escape functies gebruiken de database dus hebben ze wel een connectie nodig :-)
2 kleine puntjes:
1) Je gebruikt *soms* Nederlandse en Engelse namen door elkaar heen. Dat leest niet erg prettig.
2)
Quote:
De enige method die afwijkt van de anderen is de escape() method. Deze is static gedefinieerd aangezien er voor de uitvoer ervan niet per se een connectie met een database nodig is en er dus geen instantie van enige class nodig is.
Dat is natuurlijk niet waar, escape functies gebruiken de database dus hebben ze wel een connectie nodig :-)
Ik plaats mijn reactie die ik op phptuts heb gezet hier ook maar even.
- Een object max *normaal* 100 regels? -> Vind ik wel een gewaagde uitspraak. Werk je met user_input die je moet controleren, zijn eigenschappen van het "verzonden formulier". (zie het als een fysiek formulier) welke gecontroleerd moeten worden.
Je komt al snel over de 100 regels hoor.
- Weinig if/else statements, ligt er maar net aan of je dus controles gebruikt of niet. Daarbij kan het wenselijk zijn om loops te gebruiken, omdat je arrays als input kan gebruiken. Je roept dan een functie aan die de loop doet op de array, en de functie aanroept die steeds 1 zo'n item verwerkt. (wegens het eventueel wel van buitenaf ook rechtstreeks aan kunnen roepen van zo'n functie)
- Je geeft op het gegeven moment aan dat je voor nu even get/set methods gebruikt, maar dat je daar nog op terugkomt. Dat zie ik nergens terugkomen.
Verder een mooie en duidelijke tutorial. Voor mij wel 1 van de duidelijkste die ik heb gelezen. Jammer eigenlijk dat OOP "te groot is" om in 1 tutorial samen te vatten.
- Een object max *normaal* 100 regels? -> Vind ik wel een gewaagde uitspraak. Werk je met user_input die je moet controleren, zijn eigenschappen van het "verzonden formulier". (zie het als een fysiek formulier) welke gecontroleerd moeten worden.
Je komt al snel over de 100 regels hoor.
- Weinig if/else statements, ligt er maar net aan of je dus controles gebruikt of niet. Daarbij kan het wenselijk zijn om loops te gebruiken, omdat je arrays als input kan gebruiken. Je roept dan een functie aan die de loop doet op de array, en de functie aanroept die steeds 1 zo'n item verwerkt. (wegens het eventueel wel van buitenaf ook rechtstreeks aan kunnen roepen van zo'n functie)
- Je geeft op het gegeven moment aan dat je voor nu even get/set methods gebruikt, maar dat je daar nog op terugkomt. Dat zie ik nergens terugkomen.
Verder een mooie en duidelijke tutorial. Voor mij wel 1 van de duidelijkste die ik heb gelezen. Jammer eigenlijk dat OOP "te groot is" om in 1 tutorial samen te vatten.
"Document_PDF is fout: De DF moeten in kleine letters."
Is het in dit geval geen uitzondering omdat PDF een afkorting is?
En waarom doe je zowel Hoofdletters Per Woord EN lage streepje per woord?
DocumentPDF lijkt me toch wel de "beste" naam.
Zie ook hoe php.net zelf de naamgeving heeft van objecten en hun methodes:
http://nl.php.net/manual/en/book.dom.php
http://nl.php.net/manual/en/book.xmlreader.php
http://nl.php.net/manual/en/book.simplexml.php
Afkortingen horen gewoon met hoofdletters, samen met de 1e letter van ieder woord, zonder gebruik van lage streepjes.
Lage streepjes komen alleen voor in constanten (en bij PHP ook in de meeste functies... de logica...)
Ik raad mensen met OOP plannen aan eens de java tutorials te lezen. Ja, het is een andere taal, maar de OOP mogenlijkheden van java en PHP zijn vrijwel hetzelfde. (behalve dat je bij java meer kan dan bij PHP)
Zelf heb ik mijn OOP ook geleerd d.m.v. java, al is mijn OOP nog niet 100% "af".
Is het in dit geval geen uitzondering omdat PDF een afkorting is?
En waarom doe je zowel Hoofdletters Per Woord EN lage streepje per woord?
DocumentPDF lijkt me toch wel de "beste" naam.
Zie ook hoe php.net zelf de naamgeving heeft van objecten en hun methodes:
http://nl.php.net/manual/en/book.dom.php
http://nl.php.net/manual/en/book.xmlreader.php
http://nl.php.net/manual/en/book.simplexml.php
Afkortingen horen gewoon met hoofdletters, samen met de 1e letter van ieder woord, zonder gebruik van lage streepjes.
Lage streepjes komen alleen voor in constanten (en bij PHP ook in de meeste functies... de logica...)
Ik raad mensen met OOP plannen aan eens de java tutorials te lezen. Ja, het is een andere taal, maar de OOP mogenlijkheden van java en PHP zijn vrijwel hetzelfde. (behalve dat je bij java meer kan dan bij PHP)
Zelf heb ik mijn OOP ook geleerd d.m.v. java, al is mijn OOP nog niet 100% "af".
De naamgeving die Blanche noemt zijn letterlijk de Zend naming conventions. Dat Zend zelf de naamgeving voor hun framework beschrijven geeft al aan dat er geen duidelijk beste manier voor PHP is. Het is puur wat jezelf prettig vindt, PHP dwingt niets af.
Voordeel van de streepjes in classnames is dat het heerlijk gemakkelijk door autoload kan worden omgezet in een pad naar een bestand. Dat is lastiger (maar niet onmogelijk) wanneer je een namen als DocumentPDFDecorator zou gebruiken.
Voordeel van de streepjes in classnames is dat het heerlijk gemakkelijk door autoload kan worden omgezet in een pad naar een bestand. Dat is lastiger (maar niet onmogelijk) wanneer je een namen als DocumentPDFDecorator zou gebruiken.
@toby
Van niemand is de OOP 100% af, maar dat komt omdat iedereen het toch wel iets anders doet dan een ander het zou doen. Vaak is ook niet de 1e manier meteen beter, maar zijn het verschillende manieren om tot hetzelfde resultaat te komen.
Voor de 1 telt prestatie meer dan de leesbaarheid en andersom. 1 OOP standaard bestaat niet, en OOP is nooit 100% af. (zeker niet omdat vele programmeertalen zich ook steeds doorontwikkelen) Als je complete systemen op een goede en nette manier en met OOP kan ontwikkelen kan je gewoon OOP. Vaak kom je terwijl je bezig bent er nog achter dat er ook een andere (soms betere/ handigere) manier is om bepaalde dingen te programmeren. Als je dan al een heel eind op weg bent heb je soms niet de tijd/ zin/ mogelijkheid om helemaal terug te gaan werken om het te verbeteren/ veranderen.
Dat maakt je nog niet een mindere programmeur, er is niemand die (zonder zeer uitgebreide voorkennis) de boel in 1 keer helemaal goed en optimaal kan wegzetten.
Van niemand is de OOP 100% af, maar dat komt omdat iedereen het toch wel iets anders doet dan een ander het zou doen. Vaak is ook niet de 1e manier meteen beter, maar zijn het verschillende manieren om tot hetzelfde resultaat te komen.
Voor de 1 telt prestatie meer dan de leesbaarheid en andersom. 1 OOP standaard bestaat niet, en OOP is nooit 100% af. (zeker niet omdat vele programmeertalen zich ook steeds doorontwikkelen) Als je complete systemen op een goede en nette manier en met OOP kan ontwikkelen kan je gewoon OOP. Vaak kom je terwijl je bezig bent er nog achter dat er ook een andere (soms betere/ handigere) manier is om bepaalde dingen te programmeren. Als je dan al een heel eind op weg bent heb je soms niet de tijd/ zin/ mogelijkheid om helemaal terug te gaan werken om het te verbeteren/ veranderen.
Dat maakt je nog niet een mindere programmeur, er is niemand die (zonder zeer uitgebreide voorkennis) de boel in 1 keer helemaal goed en optimaal kan wegzetten.
@Jelmer:
Owja, ik zie het. Vreemd dat de PHP developers zelf zich niet aan die regels houden.
Persoonlijk houd ik me aan de java regels, die ik ook lekkerder vind typen. Die lage streepjes zijn irritant :P
@robert:
je OOP is niet helemaal 100% af als je bepaalde problemen niet weet op te lossen (of er moeite mee hebt) in een OOP structuur. Zo ben ik (in java) een BBCode class aan het schrijven maar weet geen goede uitwerking voor de tags zelf en hoe tagtypes te verwerken. Ik ga er denk straks eens een topicje over maken op tweakers.
Owja, ik zie het. Vreemd dat de PHP developers zelf zich niet aan die regels houden.
Persoonlijk houd ik me aan de java regels, die ik ook lekkerder vind typen. Die lage streepjes zijn irritant :P
@robert:
je OOP is niet helemaal 100% af als je bepaalde problemen niet weet op te lossen (of er moeite mee hebt) in een OOP structuur. Zo ben ik (in java) een BBCode class aan het schrijven maar weet geen goede uitwerking voor de tags zelf en hoe tagtypes te verwerken. Ik ga er denk straks eens een topicje over maken op tweakers.
Richard:
In de inleiding maak ik daar een korte opmerking over. Ik heb in eerste instantie heb ik geprobeerd om alles naar het nederlands te vertalen, maar op een gegeven moment wordt het dan echt drama. Vertalingen van termen als inheritance, visibility, etc. bestaan uiteraard wel (overerving, zichtbaarheid) maar als je dat continue in een tekst gaat verwerken waarin je refereert naar de PHP code waar het wel in het Engels staat, zie je op een gegeven moment door de bomen het bos niet meer. Vandaar de bewuste keuze om bepaalde keywords in het Engels te houden.Je gebruikt *soms* Nederlandse en Engelse namen door elkaar heen. Dat leest niet erg prettig.
Quote:
En daar heb je helemaal gelijk in! Aangepast. Het was al wat later gisterenavond dat ik dat hoofdstuk schreef.Dat is natuurlijk niet waar, escape functies gebruiken de database dus hebben ze wel een connectie nodig :-)
Robert:
- Een object max *normaal* 100 regels? -> Vind ik wel een gewaagde uitspraak. Werk je met user_input die je moet controleren, zijn eigenschappen van het "verzonden formulier". (zie het als een fysiek formulier) welke gecontroleerd moeten worden.
Ik heb de tekst iets aangepast, maar ik blijf wel bij het standpunt dat je niet snel aan 100 regels code voor een class komt. Wat betreft die user input, ik zou elke validator als apart object zien. De daadwerkelijke validatie bestaat dan nog maar uit enkele regels waarin je door de opgegeven validators heen loopt en overal validate() aanroept.
Quote:
Weinig if/else statements, ligt er maar net aan of je dus controles gebruikt of niet. Daarbij kan het wenselijk zijn om loops te gebruiken, omdat je arrays als input kan gebruiken. Je roept dan een functie aan die de loop doet op de array, en de functie aanroept die steeds 1 zo'n item verwerkt. (wegens het eventueel wel van buitenaf ook rechtstreeks aan kunnen roepen van zo'n functie)
Ook hier geldt dat je over het algemeen veel minder if/else statements zult hebben dan in alternatieve procedurele code.
Quote:
Je geeft op het gegeven moment aan dat je voor nu even get/set methods gebruikt, maar dat je daar nog op terugkomt. Dat zie ik nergens terugkomen.
De getters zijn inderdaad nog niet de prullenbak in gegaan, maar de meeste setters worden op een gegeven moment vervangen door de constructor.
Tnx voor de reacties so far!
@toby: Robert en Jelmer geven het antwoord dat ik je ook wilde geven. In de handleiding geef ik ook expliciet aan dat er veel meer conventies zijn en nodig ik de lezer uit om daar zeker naar te kijken als die van Zend hem niet bevalt.
Quote:
Dit is de conventie van het Zend Framework, maar het is niet gezegd dat het dé PHP naming convention is. Sterker nog, bij het framework wijken ze juist af van hetgeen de ontwikkelaars van PHP eerder bedacht hadden, dat geeft weer eens te meer aan dat er niet één goede manier is...Owja, ik zie het. Vreemd dat de PHP developers zelf zich niet aan die regels houden.
Ik vind het een hele goeie tutorial. Twee dingetjes die misschien nog toegevoegd zouden kunnen worden:
In het hoofdstuk over de constructor vervang je setUsername door de username gewoon mee te geven aan de constructor. Als uitleg geef je aan dat dit makkelijker is. Ik had ook een voorbeeld verwacht waarbij het eigenlijk noodzakelijk is, bijvoorbeeld een User_Store class die afhankelijk is van een instantie van PDO om te werken. Doordat je in je constructor afdwingt dat je de user_store altijd instantiëert met een instantie van PDO weet je zeker dat je user_store ook z'n pdo heeft. Wanneer je voor zo'n essentieel iets een setter zou gebruiken (wat ik veel beginners toch zie doen) heb je de rare situatie dat je de user_store hebt, maar dat hij niet werkt omdat je vergeten bent PDO er nog aan te koppelen.
In het hoofdstuk over inheritance of interfaces had je de Table class terug kunnen laten komen. Als je die een beetje aanpast zodat een Row en een Cell een eigen draw() method hebben (waar zeker iets voor te zeggen is, encapsulatie en verantwoordelijkheid) kan je het voorbeeld geven van bijvoorbeeld een StrongCell, die <strong>-tags om de content heen zet. Ik denk dat die situatie, waarbij je een class extend om hem specifiekere functionaliteit mee te geven, vaker voorkomt.
In het hoofdstuk over de constructor vervang je setUsername door de username gewoon mee te geven aan de constructor. Als uitleg geef je aan dat dit makkelijker is. Ik had ook een voorbeeld verwacht waarbij het eigenlijk noodzakelijk is, bijvoorbeeld een User_Store class die afhankelijk is van een instantie van PDO om te werken. Doordat je in je constructor afdwingt dat je de user_store altijd instantiëert met een instantie van PDO weet je zeker dat je user_store ook z'n pdo heeft. Wanneer je voor zo'n essentieel iets een setter zou gebruiken (wat ik veel beginners toch zie doen) heb je de rare situatie dat je de user_store hebt, maar dat hij niet werkt omdat je vergeten bent PDO er nog aan te koppelen.
In het hoofdstuk over inheritance of interfaces had je de Table class terug kunnen laten komen. Als je die een beetje aanpast zodat een Row en een Cell een eigen draw() method hebben (waar zeker iets voor te zeggen is, encapsulatie en verantwoordelijkheid) kan je het voorbeeld geven van bijvoorbeeld een StrongCell, die <strong>-tags om de content heen zet. Ik denk dat die situatie, waarbij je een class extend om hem specifiekere functionaliteit mee te geven, vaker voorkomt.
Waarom gebruik je per se __construct,
terwijl je ook gewoon (net zoals in bijna alle andere talen) de naam van de Class kan gebruiken.
Ook nog een kleine tip van mijn kant,, kijk maar of je het handig vind.
Maar ik maak voor iedere variable een getter en setter.
Deze setter roep ik ook aan om in de constructer variablen te zetten.
Zo kan je in je setter de foutafhandeling in bouwen.
Dan krijg je dus ongeveer dit:
output:
User Object ( [username:private] => nicoow [age:private] => 20 ) Caught exception: Age is not an Integer
Dit scheelt maar 3 regels in je constructor, maar stel je voor dat je een controle hebt van 20 regels,, dan begint dat snel aardig aan te tellen.
terwijl je ook gewoon (net zoals in bijna alle andere talen) de naam van de Class kan gebruiken.
Ook nog een kleine tip van mijn kant,, kijk maar of je het handig vind.
Maar ik maak voor iedere variable een getter en setter.
Deze setter roep ik ook aan om in de constructer variablen te zetten.
Zo kan je in je setter de foutafhandeling in bouwen.
Dan krijg je dus ongeveer dit:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
<?php
/**
* @author Nico Kaag
* @copyright 2009
*/
error_reporting(E_ALL);
class User {
private $username;
private $age;
public function User($username, $age) {
$this->setUsername($username);
$this->setAge($age);
}
public function getUsername() {
return $this->username;
}
public function setUsername($username) {
$this->username = $username;
}
public function getAge() {
return $this->age;
}
public function setAge($age) {
if (is_numeric($age)) {
$this->age = $age;
} else {
throw new Exception('Age is not an Integer');
}
}
}
try {
$user = new User('nicoow', '20');
print_r($user);
$user->setAge('12s');
} catch (Exception $e) {
echo 'Caught exception: '. $e->getMessage() ."\n";
}
?>
/**
* @author Nico Kaag
* @copyright 2009
*/
error_reporting(E_ALL);
class User {
private $username;
private $age;
public function User($username, $age) {
$this->setUsername($username);
$this->setAge($age);
}
public function getUsername() {
return $this->username;
}
public function setUsername($username) {
$this->username = $username;
}
public function getAge() {
return $this->age;
}
public function setAge($age) {
if (is_numeric($age)) {
$this->age = $age;
} else {
throw new Exception('Age is not an Integer');
}
}
}
try {
$user = new User('nicoow', '20');
print_r($user);
$user->setAge('12s');
} catch (Exception $e) {
echo 'Caught exception: '. $e->getMessage() ."\n";
}
?>
output:
User Object ( [username:private] => nicoow [age:private] => 20 ) Caught exception: Age is not an Integer
Dit scheelt maar 3 regels in je constructor, maar stel je voor dat je een controle hebt van 20 regels,, dan begint dat snel aardig aan te tellen.
@nico
edit: ik denk eigenlijk dat dat deels gedaan is zodat parent::__construct() altijd de parent-constructor aanroept. Java kent daarvoor super() (toch?) en anders zou je in PHP, al dan niet per ongeluk, een constructor kunnen overslaan of per ongeluk aanroepen omdat ze de naam hebben van de class waarvan je overerft.
Wat betreft die setters, dat is inderdaad handig (sowieso is het goed om zoveel mogelijk code op te splitsen in functies en methods) maar niet alles hoeft te kunnen veranderen. (bijvoorbeeld een berekende eigenschap uit de database, postcount bijvoorbeeld) In zo'n geval zou je de setter private kunnen maken.
Quote:
bronFor backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, it will search for the old-style constructor function, by the name of the class.
edit: ik denk eigenlijk dat dat deels gedaan is zodat parent::__construct() altijd de parent-constructor aanroept. Java kent daarvoor super() (toch?) en anders zou je in PHP, al dan niet per ongeluk, een constructor kunnen overslaan of per ongeluk aanroepen omdat ze de naam hebben van de class waarvan je overerft.
Wat betreft die setters, dat is inderdaad handig (sowieso is het goed om zoveel mogelijk code op te splitsen in functies en methods) maar niet alles hoeft te kunnen veranderen. (bijvoorbeeld een berekende eigenschap uit de database, postcount bijvoorbeeld) In zo'n geval zou je de setter private kunnen maken.
@Jelmer: bedankt voor de twee (hele goede suggesties) deze zal ik zeker meenemen zodra ik deze handleiding verder uitbreidt.
Wat betreft die set methods, dat kun je overwegen. Mijn mening is dat het in de meeste gevallen onnodig veel regels extra code oplevert, vooral voor de properties waar geen controle voor nodig is. Als ik straks het onderwerp typehinting besproken heb, heb je minder methods voor controle nodig. Enige controles die je dan wilt gebruiken, kunnen dan ook in de constructor (of eventueel een enkele set-method mocht de controle erg lang zijn).
Nico:
Dat is de methode die in PHP4 de enige mogelijkheid was en in PHP5 ook gebruikt kan worden. Naast de reden die Jelmer al noemt gebruik ik de magic method __construct() omdat ik dit ten eerste duidelijker vind maar deze method bovendien voldoet aan de naamgeving conventie die ik gebruik. De method User() doet dat niet...Waarom gebruik je per se __construct,
terwijl je ook gewoon (net zoals in bijna alle andere talen) de naam van de Class kan gebruiken.
terwijl je ook gewoon (net zoals in bijna alle andere talen) de naam van de Class kan gebruiken.
Wat betreft die set methods, dat kun je overwegen. Mijn mening is dat het in de meeste gevallen onnodig veel regels extra code oplevert, vooral voor de properties waar geen controle voor nodig is. Als ik straks het onderwerp typehinting besproken heb, heb je minder methods voor controle nodig. Enige controles die je dan wilt gebruiken, kunnen dan ook in de constructor (of eventueel een enkele set-method mocht de controle erg lang zijn).
Interessante tut!
Nu ben ik benieuwd of dit een goede opzet van mijn klasse Page is:
Met vriendelijke groet,
Boris
Nu ben ik benieuwd of dit een goede opzet van mijn klasse Page is:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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
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
<?php
/**
* CLASS
*/
class Page {
private $_id;
private $_title;
private $_content;
private $_parentId;
private $_isHome;
public function __construct($id, $title, $content, $parentId, $isHome) {
$this->_setId($id);
$this->_setTitle($title);
$this->_setContent($content);
$this->_setParentId($parentId);
$this->_setIsHome($isHome);
}
private function _setId($id) {
if(ctype_digit($id)) {
$this->_id = $id;
} else {
throw new Exception('Id is not a digit.');
}
}
private function _setTitle($title) {
if(ctype_alnum($title)) {
$this->_title = $title;
} else {
throw new Exception('Title is not alphanumaric.');
}
}
private function _setContent($content) {
$this->_content = $content;
}
private function _setParentId($parentId) {
if(ctype_digit($parentId) || $parentId === null) {
$this->_parentId = $parentId;
} else {
throw new Exception('ParentId is neither a digit nor NULL.');
}
}
private function _setIsHome($isHome) {
if($isHome == 0 || $isHome == 1) {
$this->_isHome = $isHome;
} else {
throw new Exception('IsHome is not 0 or 1.');
}
}
public function new() {
mysql_query("
INSERT INTO
pages
(
title,
content,
parent_id,
is_home
)
VALUES
(
'" . $this->_title . "',
'" . mysql_real_escape_string($this->_content) . "',
'" . $this->_parentId . "',
'" . $this->_isHome . "',
)
");
}
public function edit() {
mysql_query("
UPDATE
pages
SET
title = '" . $this->_title . "',
content = '" . mysql_real_escape_string($this->_content) . "',
parent_id = '" . $this->_parentId . "',
is_home = '" . $this->_isHome . "'
WHERE
id = '" . $this->_id . "'
");
}
}
/**
* USAGE
*/
try {
$page = new Page(null, 'Test pagina', 'Lorum ipsum...', 1, 0);
$page->new();
$page2 = new Page(1, 'Hoofd pagina', 'Lipsum lorum pipsum..', null, 1);
$page2->edit();
} catch (Exception $e) {
echo 'Caught exception: '. $e->getMessage() ."\n";
}
?>
/**
* CLASS
*/
class Page {
private $_id;
private $_title;
private $_content;
private $_parentId;
private $_isHome;
public function __construct($id, $title, $content, $parentId, $isHome) {
$this->_setId($id);
$this->_setTitle($title);
$this->_setContent($content);
$this->_setParentId($parentId);
$this->_setIsHome($isHome);
}
private function _setId($id) {
if(ctype_digit($id)) {
$this->_id = $id;
} else {
throw new Exception('Id is not a digit.');
}
}
private function _setTitle($title) {
if(ctype_alnum($title)) {
$this->_title = $title;
} else {
throw new Exception('Title is not alphanumaric.');
}
}
private function _setContent($content) {
$this->_content = $content;
}
private function _setParentId($parentId) {
if(ctype_digit($parentId) || $parentId === null) {
$this->_parentId = $parentId;
} else {
throw new Exception('ParentId is neither a digit nor NULL.');
}
}
private function _setIsHome($isHome) {
if($isHome == 0 || $isHome == 1) {
$this->_isHome = $isHome;
} else {
throw new Exception('IsHome is not 0 or 1.');
}
}
public function new() {
mysql_query("
INSERT INTO
pages
(
title,
content,
parent_id,
is_home
)
VALUES
(
'" . $this->_title . "',
'" . mysql_real_escape_string($this->_content) . "',
'" . $this->_parentId . "',
'" . $this->_isHome . "',
)
");
}
public function edit() {
mysql_query("
UPDATE
pages
SET
title = '" . $this->_title . "',
content = '" . mysql_real_escape_string($this->_content) . "',
parent_id = '" . $this->_parentId . "',
is_home = '" . $this->_isHome . "'
WHERE
id = '" . $this->_id . "'
");
}
}
/**
* USAGE
*/
try {
$page = new Page(null, 'Test pagina', 'Lorum ipsum...', 1, 0);
$page->new();
$page2 = new Page(1, 'Hoofd pagina', 'Lipsum lorum pipsum..', null, 1);
$page2->edit();
} catch (Exception $e) {
echo 'Caught exception: '. $e->getMessage() ."\n";
}
?>
Met vriendelijke groet,
Boris
@Brie: je class ziet er goed uit tot het moment dat je de methods new() en edit() definieert. Die horen er namelijk niet in thuis. Een Page object weet alleen dingen over zichzelf en kan zijn eigenschappen aanpassen, maar kan zichzelf absoluut niet toevoegen aan een database!
De communicatie met een database moet via een ander object verlopen. Binnen dat object zul je dan de beschikken hebben over een of meerdere Page objecten die je vervolgens naar de database kunt sturen:
ps. En uiteraard valt het aan te bevelen om de communicatie met de database zelf door een Database object af te laten handelen. In de class die de pagina moet opslaan, heb je dan naast het bewuste Page object ook nog een Database object nodig.
De communicatie met een database moet via een ander object verlopen. Binnen dat object zul je dan de beschikken hebben over een of meerdere Page objecten die je vervolgens naar de database kunt sturen:
Code (php)
1
2
3
4
5
2
3
4
5
<?php
public function storePage(Page $page) {
// Hier stuur je je gegevens naar de database
}
?>
public function storePage(Page $page) {
// Hier stuur je je gegevens naar de database
}
?>
ps. En uiteraard valt het aan te bevelen om de communicatie met de database zelf door een Database object af te laten handelen. In de class die de pagina moet opslaan, heb je dan naast het bewuste Page object ook nog een Database object nodig.
Typehinting werkt ook maar half in php,
Je kan deze meegeven in de parameters van een functie,, maar dat is ook alles.
En hij geeft hele mooie foutmeldingen.
Zoals:
Catchable fatal error: Argument 1 passed to User::setAge() must be an instance of integer, integer given,
Oftewel, het is een "integer" maar het moet een "integer" zijn.
In mijn ogen "integer == integer" of niet dan?
Zelfs na een Typecast doet hij het nog niet.
Overigens is het met php ook niet mogelijk om een Typehint naar iets als numeric te geven.
Je zou dan,, als het ooit gaat werken,, alles moeten gaan typecasten, omdat een Post waarde ook altijd een string is.
De controlle met is numeric werkt prima, is_int niet.
Dus tot zover de goede controlle met Typehintinh *kuch*
Overigens nog even over de constructor.
Ik programmeer in meerdere talen (voornamelijk Java en C#), en dan is het wel lekker om 1 conventie aan proberen te houden, en aangezien __construct niet werkt in Java of C#, gebruik ik in PHP maar de class name, dan werkt het iig overal, behalve in de prehistorie.
Maar ik ben toch nooit erg goed in Geschiedenis geweest.
Je kan deze meegeven in de parameters van een functie,, maar dat is ook alles.
En hij geeft hele mooie foutmeldingen.
Zoals:
Catchable fatal error: Argument 1 passed to User::setAge() must be an instance of integer, integer given,
Oftewel, het is een "integer" maar het moet een "integer" zijn.
In mijn ogen "integer == integer" of niet dan?
Zelfs na een Typecast doet hij het nog niet.
Overigens is het met php ook niet mogelijk om een Typehint naar iets als numeric te geven.
Je zou dan,, als het ooit gaat werken,, alles moeten gaan typecasten, omdat een Post waarde ook altijd een string is.
De controlle met is numeric werkt prima, is_int niet.
Dus tot zover de goede controlle met Typehintinh *kuch*
Overigens nog even over de constructor.
Ik programmeer in meerdere talen (voornamelijk Java en C#), en dan is het wel lekker om 1 conventie aan proberen te houden, en aangezien __construct niet werkt in Java of C#, gebruik ik in PHP maar de class name, dan werkt het iig overal, behalve in de prehistorie.
Maar ik ben toch nooit erg goed in Geschiedenis geweest.
@nico:
type casting werkt alleen voor object instances bij php inderdaad. Ik heb ook wel 'ff moeten lachen toen ik die genoemde error kreeg.
Misschien werkt het als je zelf een integer class maakt?
Maarja, houd het lekker bij java. Ik ben sinds kort ook begonnen aan java en vind het veel beter dan PHP.
type casting werkt alleen voor object instances bij php inderdaad. Ik heb ook wel 'ff moeten lachen toen ik die genoemde error kreeg.
Misschien werkt het als je zelf een integer class maakt?
Maarja, houd het lekker bij java. Ik ben sinds kort ook begonnen aan java en vind het veel beter dan PHP.
@nico, geef je typhinting voorbeeld code eens, want ik vermoed dat je dit hebt:
Nico, ik zal op dit onderwerp (de controles) zeker nog ingaan en daar de voor en nadelen van verschillende oplossingen tegen elkaar afzetten.
Wat betreft de constructor, het is uiteraard een persoonlijk keuze welke methode je fijner vindt werken en welke je gebruikt. Ik heb zelf beperkte ervaring in het programmeren in Java, maar ik weet hoe het daar werkt. Je zult dan ook met mij eens zijn dat de OO mogelijkheden veel groter zijn binnen Java dan binnen het (zeer) beperkte PHP. Met PHP5 is een goede stap gezet, maar het kan nog lang niet tippen aan de 'echte' OO talen.
Maar goed, we dwalen af. In PHP is het om eerder genoemde redenen waarschijnlijk verstandiger om __construct() te gebruiken. Nogmaals, het blijft een persoonlijk keuze en er is niet één goede manier aan te wijzen.
Wat betreft de constructor, het is uiteraard een persoonlijk keuze welke methode je fijner vindt werken en welke je gebruikt. Ik heb zelf beperkte ervaring in het programmeren in Java, maar ik weet hoe het daar werkt. Je zult dan ook met mij eens zijn dat de OO mogelijkheden veel groter zijn binnen Java dan binnen het (zeer) beperkte PHP. Met PHP5 is een goede stap gezet, maar het kan nog lang niet tippen aan de 'echte' OO talen.
Maar goed, we dwalen af. In PHP is het om eerder genoemde redenen waarschijnlijk verstandiger om __construct() te gebruiken. Nogmaals, het blijft een persoonlijk keuze en er is niet één goede manier aan te wijzen.
Java heeft ook wel zo z'n vreemde dingen hoor.
Zoals het verschil tussen string en String.
string is een "keyword" en String is een "Object"
Dit is ook zo voor integer en Integer.
integer kent geen toString() functie, en Integer wel.
De oplossing die jij nu geeft, kan ik me in vinden,, maar het klopt gewoon niet.
Dan kan je dus net zo goed weer een setter maken.
Zoals het verschil tussen string en String.
string is een "keyword" en String is een "Object"
Dit is ook zo voor integer en Integer.
integer kent geen toString() functie, en Integer wel.
De oplossing die jij nu geeft, kan ik me in vinden,, maar het klopt gewoon niet.
Dan kan je dus net zo goed weer een setter maken.
Edit:
@gamer
Inderdaag, heb ook Integer geprobeerd en Int en int
Maar dat mag niet baten.
@gamer
Inderdaag, heb ook Integer geprobeerd en Int en int
Maar dat mag niet baten.
Quote:
Nee, want dan kun je bijvoorbeeld vanuit een child niet meer naar de parent::__construct() verwijzen. Je zult dan altijd op de hoogte moeten zijn van de naamgeving van de methods in de parent class aangezien PHP geen andere manier kent om naar de (constructor van de) parent te verwijzen.Dan kan je dus net zo goed weer een setter maken.
Quote:
En dat kan ik niet ontkennen. Het is roeien met de riemen die je hebt, maar dan is er nog wel een verschil tussen 'efficient roeien' en 'roeien en niet vooruit komen' als je begrijpt wat ik bedoel ;-)Maar dat is toch een beetje het verhaal achter PHP,
Alles is er,, maar alles werkt eigenlijk net niet.
Alles is er,, maar alles werkt eigenlijk net niet.
Typehinting voor scalar types is niet handig in PHP omdat het een dynamic typed taal is. '1' + '1' is net zo goed 2 als 1 + 1. Daarnaast gebruikt PHP de typehints niet om de goeie method te vinden, maar puur als controle. Er wordt door PHP wel geëxperimenteerd met stevigere controle maar naar mijn idee wordt het er niet veel duidelijker op.
Ik zou liever volledige operator overloading hebben, zodat we zelf een class Integer kunnen maken, en twee instanties daarvan of iets volledig willekeurigs bij elkaar op kunnen tellen met het plus-symbool. C++ style.
Ik zou liever volledige operator overloading hebben, zodat we zelf een class Integer kunnen maken, en twee instanties daarvan of iets volledig willekeurigs bij elkaar op kunnen tellen met het plus-symbool. C++ style.
Jelmer:
Ik heb inmiddels een nieuw voorbeeld aan de handleiding toegevoegd waarin het voorbeeld van de Table class uitgebreid wordt. Deze is te vinden in de handleiding op phptuts.nl.In het hoofdstuk over inheritance of interfaces had je de Table class terug kunnen laten komen.
Tnx voor de tip! ;-)
@Nibulez:
Een interface is een blauwdruk (definitie) van een class waarin je kan defineren wat een class moet kunnen (lees: welke functies het moet hebben) zonder dat het daarbij uitmaakt hoe de class dat uitwerkt.
Je kan bijv. de interface "database" maken en deze implementeren in de classes "mysql-database" en "filebased-database". Zo heb je 2 classes met exact dezelfde functies en werking, terwijl ze hun werk op 2 totaal verschillende manieren doen.
Het nut hiervan is dat beiden objecten voldoen aan het "database"-interface, waarna je via typehinting kan opgeven dat je een object wilt van een class die het database interface gebruikt. Voorbeeld:
Deze functie accepteert nu alle objecten die het database-interface gebruiken.
Het nut van typehinting op deze manier is een verkleinde kans op bugs omdat bepaalde bugs sneller gevonden worden. Immers, als je een object geeft die het interface niet heeft krijg je nu direct een error. Zonder typehinting krijg je dan pas een error wanneer er een functie gebruikt wordt die de classe van het object mogelijk niet heeft.
Verder, OOP is een garantie voor veel meer code dan niet-OOP. Dat komt simpelweg omdat je meer structuur en overzicht aan het scripten bent, waarbij je makkelijker en sneller bugjes kan opvangen.
Een interface is een blauwdruk (definitie) van een class waarin je kan defineren wat een class moet kunnen (lees: welke functies het moet hebben) zonder dat het daarbij uitmaakt hoe de class dat uitwerkt.
Je kan bijv. de interface "database" maken en deze implementeren in de classes "mysql-database" en "filebased-database". Zo heb je 2 classes met exact dezelfde functies en werking, terwijl ze hun werk op 2 totaal verschillende manieren doen.
Het nut hiervan is dat beiden objecten voldoen aan het "database"-interface, waarna je via typehinting kan opgeven dat je een object wilt van een class die het database interface gebruikt. Voorbeeld:
Code (php)
Deze functie accepteert nu alle objecten die het database-interface gebruiken.
Het nut van typehinting op deze manier is een verkleinde kans op bugs omdat bepaalde bugs sneller gevonden worden. Immers, als je een object geeft die het interface niet heeft krijg je nu direct een error. Zonder typehinting krijg je dan pas een error wanneer er een functie gebruikt wordt die de classe van het object mogelijk niet heeft.
Verder, OOP is een garantie voor veel meer code dan niet-OOP. Dat komt simpelweg omdat je meer structuur en overzicht aan het scripten bent, waarbij je makkelijker en sneller bugjes kan opvangen.
Een interface zou je kunnen vergelijken met een opleiding. Een class die een interface implementeert kent het jargon.
Stel dat je een method "drawImageWithBorder" hebt die als eerste argument iets slikt dat in ieder geval de interface "Renderable" implementeert, en de interface Renderable zegt dat iedereen die die interface implementeert een method "render($resource)" moet hebben. Je "drawImageWithBorder" hoeft nu niet te weten wat voor argument je precies meegeeft, van wat voor class het is. Het weet zeker dat $argument->render($resource); werkt, want anders kan $argument die interface niet hebben geïmplementeerd. Puur controle dus. Of $argument nu een database, een projectie van een 3d-scene of een stuk tekst is, maakt niet uit en is niet interessant. Het voordeel daarbij van interfaces boven (abstracte) classes is dat je class niet verplicht ergens van af moet stammen. Iedere class-hiërarchie kan een interface implementeren.
Of die render() method daadwerkelijk doet wat hij moet doen, dat kan je niet controleren. Dat is gewoon een kwestie van goed programmeren en vertrouwen.
Stel dat je een method "drawImageWithBorder" hebt die als eerste argument iets slikt dat in ieder geval de interface "Renderable" implementeert, en de interface Renderable zegt dat iedereen die die interface implementeert een method "render($resource)" moet hebben. Je "drawImageWithBorder" hoeft nu niet te weten wat voor argument je precies meegeeft, van wat voor class het is. Het weet zeker dat $argument->render($resource); werkt, want anders kan $argument die interface niet hebben geïmplementeerd. Puur controle dus. Of $argument nu een database, een projectie van een 3d-scene of een stuk tekst is, maakt niet uit en is niet interessant. Het voordeel daarbij van interfaces boven (abstracte) classes is dat je class niet verplicht ergens van af moet stammen. Iedere class-hiërarchie kan een interface implementeren.
Of die render() method daadwerkelijk doet wat hij moet doen, dat kan je niet controleren. Dat is gewoon een kwestie van goed programmeren en vertrouwen.
Interfaces leveren per definitie inderdaad meer code op, maar dat gebruik je zoals in voorgaande posts al gezegd is puur om af te dwingen dat classes een bepaalde structuur hebben.
Het verschil tussen interfaces en abstract classes zit hem in het feit dat je in abstract classes wel functionaliteit kunt programmeren. Met andere woorden, daar kun je wel volledig uitgewerkte methods in opnemen. Deze functionaliteit is echter niet volledig, daarom wil je (en kun je) van een abstract class geen instantie aanmaken. Je zou dan een half object krijgen en dat werkt niet. Alle childs van een abstract class erven de gedeeltelijke functionaliteit en maken deze vervolgens compleet door minimaal de methods die als abstract gedefinieerd zijn in de parent, van functionaliteit te voorzien. De childs hebben dus een stuk functionaliteit die overeenkomt (mits de bestaande methods niet overschreven worden) en een stukje eigen functionaliteit. In dit opzicht kost het je juist minder regels code aangezien je de gedeelde functionaliteit niet telkens opnieuw hoeft te programmeren.
Het verschil tussen interfaces en abstract classes zit hem in het feit dat je in abstract classes wel functionaliteit kunt programmeren. Met andere woorden, daar kun je wel volledig uitgewerkte methods in opnemen. Deze functionaliteit is echter niet volledig, daarom wil je (en kun je) van een abstract class geen instantie aanmaken. Je zou dan een half object krijgen en dat werkt niet. Alle childs van een abstract class erven de gedeeltelijke functionaliteit en maken deze vervolgens compleet door minimaal de methods die als abstract gedefinieerd zijn in de parent, van functionaliteit te voorzien. De childs hebben dus een stuk functionaliteit die overeenkomt (mits de bestaande methods niet overschreven worden) en een stukje eigen functionaliteit. In dit opzicht kost het je juist minder regels code aangezien je de gedeelde functionaliteit niet telkens opnieuw hoeft te programmeren.
Omdat deze uitstekende tutorial wel een kickje verdient (staat hij weer bij recente reacties :+ ), en ik dit wel interessant leesvoer vind voor velen aangezien het gerelateerd is aan OOP:
http://l0calh0st.tweakblogs.net/blog/4443/database-interactie-class.html
Ok, het is zeker nog niet perfect uitgevoerd, maar leerzaam is het zeker. Lees ook de comments uiteraard, waar uitstekende feedback wordt geleverd door onder andere YopY.
http://l0calh0st.tweakblogs.net/blog/4443/database-interactie-class.html
Ok, het is zeker nog niet perfect uitgevoerd, maar leerzaam is het zeker. Lees ook de comments uiteraard, waar uitstekende feedback wordt geleverd door onder andere YopY.
http://phptuts.nl/view/45/
@blanche, sorry wist ik niet. Goede tutorials!
Zeg, in plaats van setters en getters ...
Wat vinden jullie van een systeem zoals bv. jQuery het doet?
bv.
$("mijn_selector").html() // is een getter
$("mijn_selector").html('nieuwe html') // is een setter
Je laat de parameter blanco: dan gaat de functie er van uit dat je de inhoud wil halen; geef een parameter mee en de functie gaat er van uit dat je die parameter wil setten.
Dat kan je ook perfect toepassen in dit soort omgeving.
Wat vinden jullie van een systeem zoals bv. jQuery het doet?
bv.
$("mijn_selector").html() // is een getter
$("mijn_selector").html('nieuwe html') // is een setter
Je laat de parameter blanco: dan gaat de functie er van uit dat je de inhoud wil halen; geef een parameter mee en de functie gaat er van uit dat je die parameter wil setten.
Dat kan je ook perfect toepassen in dit soort omgeving.
Is dat nog wel een getter?
Ik zou een getter definiëren als een functie die een (protected) waarde van een object retourneerd. Je hebt dan daarbij geen extra gegevens nodig.
Andere 'get' functies vragen wel iets op, maar ik zou ze geen getters noemen.
@Kris,
In dat geval is het verschil in naamgeving slechts traditie.
Ik zou een getter definiëren als een functie die een (protected) waarde van een object retourneerd. Je hebt dan daarbij geen extra gegevens nodig.
Andere 'get' functies vragen wel iets op, maar ik zou ze geen getters noemen.
@Kris,
In dat geval is het verschil in naamgeving slechts traditie.
Wat je zegt over de naamconventies is een beetje paradoxaal:
’PHP heeft zelf een DateTime class’ (moet overigens DateTime-klasse zijn)
’Document_PDF’
1. PHP overschrijdt zijn eigen regels? Ik bedoel, Document >>> UNDERSCORE <<< PDF » DateTime (geen underscore). WTF?
2. PDF mag heus wel PDF zijn. PHP doet niet aan ENV (Entity Name Validation), behalve voor klassen met de zelfde naam.
Ook je regel dat er een underscore voor beschermde eigenschappen (property=eigenschap, might you want to change that) is puur mening.
’PHP heeft zelf een DateTime class’ (moet overigens DateTime-klasse zijn)
’Document_PDF’
1. PHP overschrijdt zijn eigen regels? Ik bedoel, Document >>> UNDERSCORE <<< PDF » DateTime (geen underscore). WTF?
2. PDF mag heus wel PDF zijn. PHP doet niet aan ENV (Entity Name Validation), behalve voor klassen met de zelfde naam.
Ook je regel dat er een underscore voor beschermde eigenschappen (property=eigenschap, might you want to change that) is puur mening.
Om te reageren heb je een account nodig en je moet ingelogd zijn.
Inhoudsopgave
- Inleiding
- Object geörienteerd denken
- Foute denkwijze
- Object georiënteerd programmeren
- Visibility
- Naamgeving
- Constructor __construct()
- Voorbeeld: HTML tabel
- Inheritance
- Static methods en properties
- Abstract classes en Interfaces
- Slotwoord en referenties
PHP hulp
0 seconden vanaf nu