login  Naam:   Wachtwoord: 
Registreer je!
 Tutorials

Tutorials > PHP


Gegevens:
Geschreven door:
nemesiskoen
Moeilijkheidsgraad:
Gemakkelijk
Hits:
11573
Punten:
Aantal punten:
 (4.88)
Aantal stemmen:
8
Stem:
Niet ingelogd
Nota's:
 Lees de nota's (17)
 


Tutorial:

Technieken, tricks en tips

1. Inleiding
2. Fluent Interfaces
3. Serializeren, __sleep() en __wakeup()
4. Singelton
5. Recursie
5.1. Inleiding
5.2. Gewone recursieve functies
5.3. Wederkerig recursieve functies
5.4. Nut?
6. Template method pattern
7. Core klasse
 top
1. Inleiding
Dit artikel zal bestaan uit verschillende kleine artikeltjes die tricks en tips weggeven over PHP (waarbij ik me zoveel mogelijk ga toespitsen op 'object oriëntatie').
Op het moment van schrijven is er slechts nog maar 1 artikeltje maar hopelijk zal ik dit in de toekomst kunnen aanvullen met meerdere.
 top
2. Fluent Interfaces
Ik was laatst weer eens aan het zoeken naar nieuwe technieken in het oop gebeuren en kwam op fluent interfaces uit: http://martinfowler.com/bliki/FluentInterface.html.
Op het eerste zicht zag het er vrij raar en complex uit maar toen ik de techniek door had zag ik hoe eenvoudig het allemaal wel niet is.

In dit korte artikeltje zal ik bespreken hoe dit in zijn werk gaat.

Als voorbeeld zullen we werken met een fictieve Input klasse (waar ik later een code van zal geven). Een Input klasse is alleenstaand een beetje nutteloos maar het wordt enkel gebruikt om een voorbeeld te schetsen.

Deze Input klasse zal een HTML 'input element' terugsturen via de methode 'get()'.
Laten we aannemen dat het 'input element' slechts drie attributen heeft (hoewel het er in het echt veel meer zijn): 'type', 'name' en 'value'.

We kunnen deze attributen setten door 3 methodes aan te roepen: 'setType(type)', 'setName(name)' en 'setValue(value)'.

Dit zou dan volgende code opleveren:

<?php

$input = new Input(); 
// we zouden de waarden ook hier kunnen meegeven 

// maar dat gaan we niet doen, anders valt het hele idee weg

$input->setType('text');

$input->setName('voornaam');
$input->setValue('Koen');
// setten

echo $input->get();

// weergeven

?>


Via fluent interfaces kan bovenstaande code een hoop worden verkort.
Er kunnen drie regels worden weggelaten.

<?php

$input = new Input();

echo $input->setType('text')->setName('voornaam')->setValue('Koen')->get();


?>


Hoe komt het nu dat dit zou werken vraag je jezelf misschien af.
Het antwoord is eenvoudig, elke methode (buiten de laatste) moet $this terugsturen.
Een voorbeeldclass zou er dan als volgt uitzien:

<?php

class Input {

  var $type;
  var $name;
  var $value;

  function Input() {} /* kan nog iets komen */


  function setType($type) {
    $this->type $type;
    return $this;
  }

  function setName($name) {

    $this->name $name;
    return $this;
  }
  
  function setValue($value) {

    $this->value $value;
    return $this;
  }

  function get() {
    return '<input type="' $this->type '" name="' $this->name '" value="' $this->value '" />';

  }

}

?>

De grote vraag die we ons moeten stellen is: is dit bevorderlijk qua leesbaarheid. Dit kan van persoon tot persoon afhangen.
Als je aan een project in groep begint moet je dus de vraag stellen 'gaan we dit gebruiken'.

Ook ga je moeten oppassen en onthouden welke methodes nu juist '$this' terugsturen en welke niet.
Het is een experimentele techniek die soms handig kan zijn en in andere gevallen niet.
Tri Pham deelde in zijn blog mee dat dit bij een DAL (Database Abstraction Layer) mooi zou kunnen staan.

<?php
$dal->select('naam_kolom, adres_kolom')->from('naw')->where('leeftijd=15');

// source: http://www.scriptorama.nl/algemeen/fluent-interfaces
?>
 top
3. Serializeren, __sleep() en __wakeup()
In dit kleine artikeltje zal ik het serializeren van een object bespreken.
Dit is een oude forumpost van mij waarvan ik denk dat het nog nut kan hebben.

__sleep en __wakeup heb je nodig wanneer je je object serialiseerd. Dit betekend de waardes onthouden en deze in string formaat opslaan. Zo kan je dus een heel object in 1 databaserow opslaan. Het probleem is dat serialize nogal wat problemen heeft met results. Deze waarden kunnen niet geserializeerd worden. Je kan PHP de opdracht geven deze variabelen te laten 'slapen'. Bij de aanroep van __wakeup() ga je deze variabelen weer 'setten'...

Denk er aan dat een instantie van een class (het object) deserializeren alleen kan op een pagina waar de class definitie voorkomt.

Een voorbeeld hiervan vind je hieronder

<?php

class Test {

   public function __construct($var$foo$bar) {


      list($this->tvar$this->foo$this->bar) = array($var$foo$bar);


   }

   function __sleep() {

     // deze vars zullen mee geserializeerd worden

     return array('tvar''foo');


   }

   function __wakeup() {

     $this->bar "blaat";

   }

   public function run() {


     echo $this->tvar $this->foo $this->bar;

   }

   private $tvar;

   private $foo;
   private $bar;

}

$test = new Test('blaat''blaat2''blaat3');

$test serialize($test); // __sleep wordt aangeroepen
$test unserialize($test); // __wakeup wordt aangeroepen

$test->run(); // 'blaatblaat2blaat'
?>
 top
4. Singelton
Het singleton pattroon is een "design pattern" dat er voor zorgt dat je een beperkt aantal instances van een class kan maken.
Het is mogelijk om het te beperken tot 1 of een klein aantal.

De eerste vraag die je moet beantwoorden voor je hieraan begint is 'waarom zou ik dat willen?'.
Het antwoord is heel simpel: 'in sommige gevallen is het nutteloos om 2 instances te maken'.
Om een voorbeeld te geven:
- een MySQL-klasse, je gaat bij een standaard applicatie niet direct met meerdere db's verbinden of proberen te verbinden op 1 pagina
- een Core-klasse, je gaat maar één klasse gebruiken om andere klasses in te laten. Denk maar aan het "ZEND FRAMEWORK"
- een Settings-klasse, je hebt maar 1 paar instellingen. Dit hangt er natuurlijk af van wat voor settings je gebruikt. Als het om db-settings gaat heb je maar 1 paar, gaat het om eender wat kan je er meerdere hebben.
- en zo kan je nog duizend en één voorbeelden geven
- ...

En nu aan de slag:
hoe gaan we dit verwezenlijken.

Eerst en vooral gaan we het creëeren van een instantie vanaf buiten de klasse onmogelijk maken.
Dit lijkt moeilijker dan het is, volgende code zorgt hiervoor:

<?php

class Singleton {

  private function __construct() {}
  private function Singleton() {}
  

  // zowel php5 als php4 constructor blokkeren
  
}

?>

Het is nu praktisch onmogelijk om volgende code uit te voeren:

<?php

$eenObject = new Singleton();

?>

Omdat er dan een private methode wordt aangeroepen.

Nu schiet waarschijnlijk de vraag teboven: hoe kan ik dan wel een instantie maken.
Hiervoor moeten we eerst de volgende vraag antwoorden: hoeveel instanties wil ik hebben.
Laten we aannemen dat we er één willen.

Volgende code zal dan deze instantie verlenen:

<?php


class Singleton {

  static private $instance NULL;

  // we zouden hier een teller kunnen bijhouden met het aantal instanties zodat we het kunnen verhogen tot 2 of 3


  private function __construct() {}
  private function Singleton() {}
  // zowel php5 als php4 constructor blokkeren

  
  static public function createInstance() {
  
    if(self::$instance == NULL) {
      self::$instance = new self;

    }
    
    return self::$instance;
    
  }
  
  public function aFunction() {
  
    echo "Ik wordt aangeroepen";

    
  }
  
}

?>

Volgende code laat ons toe om een instantie te maken. Deze wordt op volgende manier aangeroepen.

<?php

$eenObject Singleton::createInstance();
$eenObject->aFunction();

?>

Je moet natuurlijk niet overal Singleton gaan gebruiken omdat je vindt dat het mooi staat. Gebruik het wanneer je het nodig hebt!
 top
5. Recursie

5.1. Inleiding

Recursie is een interessante techniek met vele voordelen, Fenrir heeft ze ooit eens besproken maar dat artikel is verdwenen. Daarom probeer ik het opnieuw te documenteren zodat mensen dit kunnen ontdekken en gebruiken.

Recursie komt niet alleen voor bij programmeertalen maar ook bij taal en wiskunde. Recursie betekend 'zelf-verwijzing'. PHP is een recursief acroniem: een afkorting die naar zichzelf verwijst. PHP staat voor: 'PHP Hypertext Preprocessor', het woord PHP komt voor in de afkorting ervan. Een ander voorbeeld is GNU: 'GNU's Not Unix'.

Een ander voorbeeld is bijvoorbeeld wanneer je met een webcamera een filmpje maakt en dit rechtstreeks afspeelt op de computer. Als je dan met de camera naar het computerscherm kijkt dan blijft het beeld zich oneindig diep herhalen. Een voordeel van recursie bij programmeertalen is dat we het kunnen beïnvloeden en dus op tijd laten stoppen.

Een alternatief voor recursie is iteratie, denk maar aan de 'for'- en 'while'-loop. Toch kan je met recursie net iets meer, je kan veel dieper verwijzen.

Er zijn twee vormen van recursieve functies binnen PHP:
- Gewone recursieve functies
- Wederkerig recursieve functies

We beginnen met de gewone te bespreken, of in ieder geval: het maken ervan.

 top
5.2. Gewone recursieve functies

Om te beginnen ga ik eerst een klein voorbeeldje van iteratie geven. We gaan een tellertje maken dat van 5 naar 0 telt.

<?php

for($i 5$i >= 0$i--) {

  echo 
$i "<br />";

}

?>

Bovenstaand voorbeeld is een basisvoorbeeld van herhaling, om hetzelfde resultaat te bekomen met recursie moet je een functie maken die zichzelf aanroept. In de functie moet een voorwaardelijke constructie (if) zitten zodat je geen oneindige loop krijgt.

<?php

function countDown($teller 5) {

   if(
$teller >= 0) {

      echo 
$teller "<br />";
      
countDown(--$teller);

   }

}

?>

We zullen dit stukje code stap voor stap analyseren. We maken een functie aan genaamd 'countDown' en geven deze een standaardargument mee namelijk '$teller'. Als deze niet is 'geset' heeft deze de waarde 5, anders de gesette waarde. Vervolgens gaan we kijken of teller groter of gelijk is aan 0, zoja dan gaan we verder, zo nee: dan stopt het programma. We gaan nu het getal op het scherm weergeven en als laatste roept de functie zichzelf aan met de de waarde van $teller min 1.

 top
5.3. Wederkerig recursieve functies

Volgend voorbeeld demonstreert wat wederkerig recursieve functies zijn en doen.
<?php

function recursief_1($arg) {

    if(
$arg 0) {
        
        echo 
$arg "<br />";
        
        
recursief_2($arg 2);
        
    }
    
}

function 
recursief_2($arg) {

    if(
$arg 0) {
    
        echo 
$arg "<br />";
        
        
recursief_1(++$arg);
        
    }

}

recursief_1(10);

?>

Wat gebeurt er nu?
Eerst wordt de functie 'recursief_1' aangeroepen met het argument 10. Dit wordt weergegeven en de functie 'recursief_2' wordt aangeroepen met de waarde van $arg (10) min 2. De functie 'recursief_2' ontvangt dan het argument 2. Om het als een stappenplan op te schrijven:

10 wordt meegegeven als argument aan de functie 'recursief_1'.
8 wordt meegegeven als argument aan de functie 'recursief_2'.
9 wordt meegegeven als argument aan de functie 'recursief_1'.
7 wordt meegegeven als argument aan de functie 'recursief_2'.
8 wordt meegegeven als argument aan de functie 'recursief_1'.
6 wordt meegegeven als argument aan de functie 'recursief_2'.
7 wordt meegegeven als argument aan de functie 'recursief_1'.
5 wordt meegegeven als argument aan de functie 'recursief_2'.
6 wordt meegegeven als argument aan de functie 'recursief_1'.
4 wordt meegegeven als argument aan de functie 'recursief_2'.
5 wordt meegegeven als argument aan de functie 'recursief_1'.
3 wordt meegegeven als argument aan de functie 'recursief_2'.
4 wordt meegegeven als argument aan de functie 'recursief_1'.
2 wordt meegegeven als argument aan de functie 'recursief_2'.
3 wordt meegegeven als argument aan de functie 'recursief_1'.
1 wordt meegegeven als argument aan de functie 'recursief_2'.
2 wordt meegegeven als argument aan de functie 'recursief_1'.

 top
5.4. Nut?

Wat is nu het nut van recursieve functies denk je nu misschien. Ten eerste: je kan oneindig diep gaan zoeken in een array, natuurlijk is daarvoor de functie 'array_map()' die een functie kan uitvoeren op een gehele array. Je kan bijvoorbeeld ook een gehele directory uitlezen, je kan stoppen wanneer je wil, je kan een bestand unzippen en ga maar door. Je zou bijvoorbeeld een array tot drie lagen diep kunnen doorzoeken en dan stoppen.

Waar het ook voor gebruikt wordt is 'brute force'. Je kan alle mogelijke combinaties kunnen afgaan en blijven afgaan tot je het hebt. Met recursie heb kan je met variabele lengtes werken.

Een voorbeeldje van hoe je een array kan uitlezen met recursie (zonder gebruik van 'array_map') vind je hieronder.

<?php

function lees_array($array) {

    echo 
"<ul>";

    foreach(
$array as $k => $v) {
    
        echo 
"<li>";
        
        if(
is_array($v)) {
        
            echo 
$k ":";
            
            
lees_array($v);
                
        } else {
            
                echo 
$k ": " $v;
                
        }
        
        echo 
"</li>";
        
    }
    
    echo 
"</ul>";
    
}

$array = array(    
                
=> "Dit staat als eerste",
                
=> "Dit als tweede",
                
=> array(
                            
"3.1" => "Dit staat in een onderverdeling",
                            
"3.2" => "Dit ook"
                
)
        );
        
    
lees_array($array);

?>

De output zal er dan zo uitzien.
  • 1: Dit staat als eerste
  • 2: Dit als tweede
  • 3:
    • 3.1: Dit staat in een onderverdeling
    • 3.2: Dit ook

Hopelijk zal recursie voortaan het scripten voor jou versnellen, ik vind het in ieder geval een van de handigste dingen technieken het programmeren. Je kan er zoveel mee zonder veel te moeten doen.

 top
6. Template method pattern
Het template method pattern is een patroon dat je in staat stelt in grote lijnen te omschrijven hoe je code gaat verlopen.
Je gaat bijvoorbeeld van een Mens een klasse maken.

Deze klasse wil je later onderverdelen onder culturen.
Dus dat je mensen hebt uit verschillende culturen.

Over het algemeen kan je stellen dat elke Mens veel gelijkenissen vertoond qua acties:
- slapen
- opstaan
- eten
- bezigheid van de dag
- eten
- slapen

Tussen deze culturen verschillen de stappen.
Zo gaat bijvoorbeeld iemand van de westerse wereld werken terwijl Indianen (laten we even stellen dat ze nog leven zoals vroeger) gaan jagen.
De armeren onder ons gaan eten zoeken.
Wij slapen in een huis, Indianen in een wigwam, ...

Wat je wel kan stellen is dat voor elke mens deze stappen worden ondernomen (en dan gaan we niet op uitzonderingen zoeken).

Zo kunnen we dus een algemene mens klasse maken

<?php

abstract class Mens {

  abstract function slapen();
  abstract function opstaan();

  abstract function eten();
  abstract function bezigheid();
  
  final function dagVerloop() {
    $this->slapen();

    $this->opstaan();
    $this->eten();
    $this->bezigheid();
    $this->eten();
    $this->slapen();

  }
  
}

?>

We declareren de laatste methode final omdat deze niet meer mag veranderen.
Hier kan bijvoorbeeld ook een ingewikkeld algoritme staan om dingen te berekenen die in sommige klassen op exact dezelfde manier berekend moeten worden maar dan met andere waardes.

Via bovenstaande template kunnen we nu de culturen gaan inbouwen.

Een voorbeeldcode vind je hieronder:

<?php

abstract class Mens {

  abstract function slapen();
  abstract function opstaan();

  abstract function eten();
  abstract function bezigheid();
  
  final function dagVerloop() {
    $this->slapen();

    $this->opstaan();
    $this->eten();
    $this->bezigheid();
    $this->eten();
    $this->slapen();

  }
  
}

class Westers extends Mens {

  function slapen() {
  
    echo "Ik lig in een bed<br />";

    
  }
  
  function opstaan() {
  
    echo "Ik sta op en kleed mij aan<br />";

    
  }
  
  function eten() {
  
    echo "Ik doe de koelkast open en pak eten<br />";

    
  }
  
  function bezigheid() {
  
    echo "Ik stap in de auto. Ik rijd naar het werk. Ik doe mijn werk. Ik ga middageten. ...<br />";

    
  }
  
}

class Indiaan extends Mens {

  function slapen() {
  
    echo "Ik lig onder een matje in mijn WigWam<br />";

    
  }
  
  function opstaan() {
  
    echo "Ik sta op<br />";
    

  }
  
  function eten() {
  
    echo "Gelukkig ben ik gisteren gaan jagen, nu kan ik eten<br />";

    
  }
  
  function bezigheid() {
  
    echo "Ik pak mijn pijl en boog en ga jagen<br />";

    
  }
  
}

$jan = new Westers;
$jan->dagVerloop();

echo "<hr />";


$rodeBeer = new Indiaan;
$rodeBeer->dagVerloop();

?>

Het wordt allemaal misschien een beetje grof voorgesteld maar het gaat om de techniek, niet om de inhoud.

 top
7. Core klasse
Een techniek die ik heb leren appreciëren door het ZEND Framework te bestuderen is het 'inladen van andere klasses doormiddel van een core klasse'.
Hierdoor kan je bepaalde klassen inladen doormiddel van 1 grote klasse deze te opdracht te geven.

Stel je library bestaat uit 20 klassen (een form klasse, een upload klasse, een validate klasse, enzovoort).
Je kan deze dan 1 maal in config.php inladen en dit bestand overal 'includen' maar hierdoor zullen onnodige klasse definities voorkomen.

Daarom is er een techniek ontworpen om ze alleen maar in te laden wanneer je ze nodig hebt, met een zo eenvoudig mogelijke code.

Deze core klasse zal volgens het singleton patroon worden opgebouwd.

<?php

class Core {

  private function __construct() {}
  private function Core() {}

  
}

?>

Hierboven kan je het begin hiervan zien.
Ik ga deze Core klasse uitbreiden tot een deftige basis, niet zoiets complex en geavanceerd als de Zend klasse.

We beginnen met een 'inlaadmodule'. Het is de bedoeling dat we uiteindelijk alleen maar op volgende manier een klasse moeten laten.

<?php

$myInput Core::loadModule("Core_Form_Input");

// dit zou dan synoniem moeten zijn voor $myForm = new Core_Form_Input;

?>

Zend Framework heeft een leuk ideetje gevonden om te kunnen weten waar deze klasse zich bevind, namelijk door de _ te vervangen door /.
Zo kan het eenvoudig de directory uitlezen.
De Input klasse bevindt zich dan in de map Core/Form/ en het bestand heet Input.php.

We zullen eens kijken naar de methode 'loadModule'.

<?php

class Core {

  private function __construct() {}
  private function Core() {}
  // Singleton
  

  static public function loadModule($theClass) {
  
    $the_file str_replace("_""/"$theClass) . ".php"// nu krijgen we Core/Form/Input.php

    
    if(self::isReadable($the_file)) {
      //bestaat deze file wel
      
      require_once $the_file// we hoeven hem maar 1maal in te laden, 
// zo kan de klasse meerdere keren worden aangeroepen 
// maar moet het maar 1maal worden ingeladen       
return new $theClass;            } else {            return false;            }      }         /**    * functie gekopieerd van ZEND FRAMEWORK   * Map: /   * File: Zend.php   * Class: Zend   * Original author: Zend   **/     static public function isReadable($filename)     {         $f = @fopen($filename'r'true);         $readable is_resource($f);         if ($readable) {             fclose($f);         }         return $readable;     }    } $input Core::loadModule("Core_Form_Input"); ?>

De Zend Core bevat veel meer dan deze functie, het kan ook interfaces inladen, het kan op een uitgebreide manier bestanden inladen, enzovoort.
Dit is slechts om een basis idee te geven voor een Core, niemand houdt je tegen om verder te bouwen.
 top

« Vorige tutorial : CURL nader verklaard Volgende tutorial : Wees voorbereid op een php5 migratie »

© 2002-2024 Sitemasters.be - Regels - Laadtijd: 0.012s