login  Naam:   Wachtwoord: 
Registreer je!
 Nota's op tutorial:

Tutorials > PHP > OOP (Object Oriented Programming)
Pagina:

Reacties op de tutorial OOP (Object Oriented Programming)


Offline  Joost
Gepost op: 03 januari 2014 - 15:38
PHP expert

De backslashes zijn bij de namespaces weggevallen.

Offline  Wijnand
Gepost op: 03 januari 2014 - 20:44
Moderator

Hoi Joost, dank je wel voor het melden. Dit klopte inderdaad en als het goed is heb ik dit nu aangepast.

Tijdens het converteren naar een php pagina is dit fout gegaan. Nogmaals bedankt voor het melden. Als je nog inhoudelijke of andere opmerkingen hebt hoor ik het graag.

Offline  Thomas
Gepost op: 04 januari 2014 - 21:33
Moderator

Object Orientated Programming? Die kende ik nog niet .

Wijnand schreef:
Use DevModulesAccountsUser as Account;
Door de backslash geef je aan dat deze namespace buiten de huidige namespace zit en dat je de hele namespace-naam gaat opgeven van de class die je wilt selecteren. Door 'as' te gebruiken geef je aan dat je die class 'User' (van de betreffende namespace) met de naam 'Account' wil gebruiken.

Maar vervolgens gebruik je in het voorbeeld User:: . Zou dat niet Account:: moeten zijn? Het idee van het gebruik van "as" is toch het definiëren van een alias als ik het goed begrijp? Niet echt zinnig als je die dan vervolgens niet gebruikt .

Over __get()
Ik zou toch een soort van controle inbouwen die kijkt of de property bestaat? Dat zou je kunnen doen in combinatie met __isset(), dus bijvoorbeeld met if ($this->__isset($key)) of zelfs if (self::__isset($key)) (EDIT: als je een object van een class gebruikt is $this beter/intuitiever; als je static properties set/get/controleert op bestaan gebruik je self:: )? En anders die() / throw exception of wat dan ook.

Over __isset()
Het voorbeeld klopt volgens mij niet helemaal? Die accepteert namelijk alles (return true lol). Als de Test class voortborduurt op de eerdere variant waarin __get() en __set() worden gebruikt zou dit dus zoiets moeten worden (met hierbij ook aangepaste __get()):
  1. <?php
  2. class Test {
  3. ...
  4. public function __isset($key) {
  5. return isset($this->columns[$key]);
  6. }
  7. ...
  8. public function __get($key) {
  9. if ($this->__isset($key)) {
  10. return $this->columns[$key];
  11. } else {
  12. // complain!
  13. // die(), throw new Exception() or whatever.
  14. }
  15. }
  16. ...
  17. }
  18. ?>


Variable aantal opties
Vaak wil je bij de creatie van een object allerlei (waarden van) eigenschappen meegeven, maar het kan handig zijn als je deze niet hoeft in te stellen als deze al een default waarde hebben. Door wat truuks met arrays kun je dit eenvoudig doen:
  1. <?php
  2. class LotsOfProperties
  3. {
  4. protected $properties;
  5.  
  6. public function __construct($properties=array()) {
  7. $this->properties = $properties + self::getDefaultProperties(); // first overwrites second
  8. }
  9.  
  10. public function getProperties() {
  11. return $this->properties;
  12. }
  13.  
  14. protected static function getDefaultProperties() {
  15. return array(
  16. 'width' => 640,
  17. 'height' => 480,
  18. 'mime' => 'image/gif',
  19. 'colors' => 16,
  20. );
  21. }
  22. }
  23.  
  24. // Everything with default settings.
  25. $test = new LotsOfProperties();
  26. echo '<pre>'.print_r($test->getProperties(), true).'</pre>'; // not safe, still needs escaping
  27. // prints:
  28. /*
  29. Array
  30. (
  31.   [width] => 640
  32.   [height] => 480
  33.   [mime] => image/gif
  34.   [colors] => 16
  35. )
  36. */
  37.  
  38. // Custom width and colors.
  39. $test = new LotsOfProperties(array('width' => 800, 'colors' => 256));
  40. echo '<pre>'.print_r($test->getProperties(), true).'</pre>'; // not safe, still needs escaping
  41. // prints
  42. /*
  43. Array
  44. (
  45.   [width] => 800
  46.   [colors] => 256
  47.   [height] => 480
  48.   [mime] => image/gif
  49. )
  50. */
  51. ?>


De "+" operator op arrays doet het volgende: als A en B arrays zijn en je doet C = A + B, dan zullen alle values bij alle keys die in A en B voorkomen worden overschreven met de waarden van A (in resultaat-array C)... Onthoud gewoon "de eerste overschrijft de tweede" (first overwrites second).

Je zou natuurlijk ook nog kunnen controleren of de properties die je probeert in te stellen geldig zijn, je zou dus ook nog een whitelist (met typechecks, als je dat leuk vindt) kunnen meenemen.

abstract classes en interfaces
Het verschil tussen deze twee snap ik zelf ook nog niet helemaal, maar volgens mij is het zoiets:
Zoals een Class een blauwdruk is voor een Object, is een abstract Class een blauwdruk voor een andere Class die hiervan afgeleid is.
Als een Class ook maar één abstractie property of method heeft, wordt daarmee de hele Class abstract (moet dan als zodanig gedefinieerd worden).
Een abstract Class heeft meestal al enkele methoden geimplementeerd (of heeft al enkele properties gedefinieerd), andere moeten in de afgeleide Class(es) geimplementeerd worden.

Een interface is meer een soort van voorschrift. In een interface implementeer je niets, je definieert alleen maar methoden. Als een andere klasse een interface implementeert, dan MOETEN al deze interface-methoden hier in zitten, eigenlijk hetzelfde dus als abstracte methoden... Een interface schrijft voor WAT er geimplementeerd moet worden, maar niet HOE.

Een ander verschil tussen interfaces en abstracte Classes is dat een Class slechts een afgeleide kan zijn van één hoger gelegen (en mogelijk abstracte) Class (Class A extends B), maar tegelijkertijd méérdere interfaces kan implementeren (Class A extends B implements X, Y, Z).

Stel bijvoorbeeld dat je een ResultSet interface hebt in je database abstractie laag. Deze beschrijft dus welke methoden alle afgeleide classes zouden moeten implementeren. Maar elke implementatie is specifiek voor het database-type. Je zou dan dus zoiets kunnen doen (correct me if I'm wrong):

  1. <?php
  2. // This is what we expect to be implemented in any database-type resultset functionality:
  3. interface DatabaseResult
  4. {
  5. public function fetchRow();
  6.  
  7. public function fetchValue();
  8.  
  9. public function numRows();
  10.  
  11. public function dataSeek($offset);
  12.  
  13. public function freeResult();
  14. }
  15.  
  16. // This is a (uniform) database layer implementation for the the (specific) MySQLi variant, we use the functionality that the MySQLi class already offers, we extend upon it!
  17. class DatabaseResultMySQLi extends MySQLi_Result implements DatabaseResult
  18. {
  19. // Returns an associative array.
  20. public function fetchRow() {
  21. return $this->fetch_assoc();
  22. }
  23.  
  24. // Returns a single value, for COUNT queries and such.
  25. public function fetchValue() {
  26. $row = $this->fetch_row();
  27. return $row[0];
  28. }
  29.  
  30. public function numRows() {
  31. return $this->num_rows;
  32. }
  33.  
  34. public function dataSeek($offset) {
  35. return $this->data_seek($offset);
  36. }
  37.  
  38. public function freeResult() {
  39. $this->free();
  40. }
  41. }
  42. ?>

Offline  Thomas
Gepost op: 05 januari 2014 - 10:36
Moderator

Je kunt ook parent-child (boom)structuren inbouwen in een class, bijvoorbeeld een geneste div-structuur:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  5. <title>nested divs</title>
  6. </head>
  7.  
  8. <body style="margin: 50px; font-family: sans-serif;">
  9. <?php
  10. class NestedDiv
  11. {
  12. protected $name;
  13. protected $style;
  14. protected $parent;
  15. protected $buffer;
  16. protected $children;
  17.  
  18. public function __construct($name='', $style='', $parent=null) {
  19. $this->name = $name;
  20. $this->style = $style;
  21. $this->parent = $parent;
  22. $this->children = array();
  23. if ($parent) {
  24. $parent->addChild($this);
  25. }
  26. }
  27.  
  28. protected function addChild($object) {
  29. $this->children[] = $object;
  30. }
  31.  
  32. public function printDiv() {
  33. if (count($this->children)) {
  34. // buffer lower levels
  35. foreach ($this->children as $child) {
  36. $child->printDiv();
  37. }
  38. $this->buffer = ob_get_clean();
  39. }
  40.  
  41. // print current level
  42. ?><div style="<?php echo $this->style ?>">
  43. <?php
  44. // did we have multiple (floating) children? (your styles should reflect this too, obviously)
  45. if (count($this->children) > 1) {
  46. // print the name, then add a wrapper and clear div
  47. echo $this->name;
  48. ?><div><?php
  49. if (count($this->children)) {
  50. echo $this->buffer;
  51. }
  52. ?><div style="clear: both;"><!-- empty --></div>
  53. </div><?php
  54. } else {
  55. // otherwise just print stuff
  56. echo $this->name;
  57. if (count($this->children)) {
  58. echo $this->buffer;
  59. }
  60. }
  61. ?></div><?php
  62. }
  63. }
  64.  
  65. // root div
  66. $rootdiv = new NestedDiv('one', 'width: 90%; padding: 5%; background-color: #f0f0ff;');
  67. // child div with $rootdiv as parent
  68. $div2 = new NestedDiv('two', 'width: 90%; padding: 5%; background-color: #d0d0ff;', $rootdiv);
  69. // two floating divs on the same level, both having $div2 as parent
  70. $div3_1 = new NestedDiv('three left', 'float: left; width: 40%; padding: 5% 4% 5% 5%; margin: 0 1% 0 0; background-color: #b0b0ff;', $div2);
  71. $div3_2 = new NestedDiv('three right', 'float: left; width: 40%; padding: 5% 5% 5% 4%; margin: 0 0 0 1%; background-color: #b0b0ff;', $div2);
  72. // a child div that has $div3_2 (the right floating div) as parent
  73. $div4 = new NestedDiv('four right', 'width: 90%; padding: 5%; background-color: #9090ff;', $div3_2);
  74.  
  75. // print the ROOT div inside a box with an absolute width)
  76. ?><div style="width: 800px">
  77. box
  78. <?php echo $rootdiv->printDiv() ?>
  79. </div>
  80. </body>
  81. </html>


EDIT: In dit voorbeeld is het niet echt nodig om output te bufferen, maar stel nu dat in de printDiv-methode (die dan waarschijnlijk anders zou heten) informatie doorgeeft aan een bovengelegen div? Als je geen output buffering zou gebruiken zou dit niet kunnen, immers de bovengelegen div is al afgedrukt, je kunt die dan niet meer aanpassen.

Maar stel nu dat je dit voorbeeld doortrekt naar de volgende situatie: je buitenste div is een "maintemplate" van een webpagina en een lager gelegen div is code die je op specifieke pagina's uitvoert, bijvoorbeeld artikel-pagina's. Je zou dan met deze buffertechniek nog zaken kunnen aanpassen in het maintemplate. Denk hierbij aan het toevoegen van verwijzingen naar CSS- of JavaScript-bestanden of het instellen van de <title>-tag van de maintemplate op grond van de titel van een artikel.

Offline  Wijnand
Gepost op: 21 januari 2014 - 10:20
Moderator

Bedankt voor je opmerkingen. Volgens mij heb ik de dingen die echt fout waren (die jij aangaf) eruit gehaald. De voorstellen, daar ga ik verder over na denken. Het klopt inderdaad dat interfaces 'slechts' voor structuur zijn, dat je daar geen gegevens in kunt vullen, maar dat het een blauwdruk is van de dingen die perse in een bepaalde class moeten.

Offline  Thomas
Gepost op: 12 augustus 2014 - 12:39
Moderator

> Meer over autoloading

Offline  Pluys
Gepost op: 30 januari 2015 - 14:01
Nieuw lid

Het is een kleinigheid, een tikfout. Scope Resulation Object moet zijn Scope Resolution Object 

Pagina:

Enkel aanvullende informatie is welkom. Geen prijzende of afkeurende reacties.
 
© 2002-2024 Sitemasters.be - Regels - Laadtijd: 0.074s