wiki.phpfreakz.nl
Aanmelden Artikel Overleg Bewerk Geschiedenis Go to the site toolbox

Object Oriented Programming

Object Oriented Programming, ook wel afgekort tot OOP, is een manier van programmeren waarbij je al je code in classes stopt. Deze classes hebben een bepaalde structuur, waardoor je code simpel kunt terugvinden en de code makkelijk uit te wisselen is. Vaak omschrijf je de structuur van classes via verantwoordelijkheden:

Een instantie van een class Person bevat een naam en leeftijd

Door deze verantwoordelijkheden in een contract te zetten is het overbodig om de implementatie van de class te kennen om gebruik te kunnen maken van de class. Meer informatie hierover staat in het hoofdstuk 'Design by contract'

Een ander interessant aspect van OOP, zijn Design Patterns. Een design pattern lost een bepaald veelvoorkomend probleem op door een structuur van je classes voor te stellen.

Sinds versie 5 biedt PHP goede ondersteuning voor OOP. Dit artikel laat het concept achter OOP zien.

Inhoud

Waarom OOP?

Er zijn verschillende redenen waarom je zou willen beginnen met OOP. Enkele redenen kunnen zijn:

  • Je wilt graag structuur in je code aanbrengen
  • Je wilt je code kunnen hergebruiken tussen verschillende projecten
  • Je wilt de leesbaarheid van je code vergroten
  • Via design patterns kan je snel problemen oplossen
  • Je moet je code uitwisselen met collega's en die collega's moeten jouw code ook begrijpen.

OOP is prima toe te passen in web applicaties. Alle bovenstaande redenen zijn namelijk ook van toepassing op dit soort applicaties. PHP is een taal die je veel dingen altijd opnieuw laat doen, het is natuurlijk ideaal om één keer hier de code voor te schrijven en die vervolgens in al je andere projecten te kunnen hergebruiken.

Een kleine opmerkingen ten aanzien van OOP is wel belangrijk. Veel mensen denken dat OOP gewoon een kwestie is van alle (ouderwetse) procedurele code in een klasse gooien. OOP is echter veel meer dan dat: het is een denkwijze. Het is helaas ook een denkwijze waar je rustig de tijd voor moet nemen.

Classes

Binnen OOP spelen classes een belangrijke rol. Een class beschrijft een bepaalde verantwoordelijkheid. Deze verantwoordelijkheden worden vaak opgesplitst in drie onderdelen:

  • Eigenschappen: dingen die de class weet
  • Queries: dingen die je aan de class kan vragen (verwar dit niet met SQL queries)
  • Commando's: dingen die de class voor je kan doen

Het onderstaande voorbeeld bevat een class die al deze onderdelen bevat.

<?php
class Person {
 
  // De eigenschap naam
  private $sName;
  // De eigenschap leeftijd
  private $iAge;
 
  // De constructor die de naam van de persoon op geeft
  public function __construct($sName){ 
    $this->sName = $sName; 
  } 
 
  // De query die de naam van deze persoon geeft
  public function getName(){ 
    return $this->sName; 
  }
 
  // De query die de leeftijd van deze persoon geeft
  public function getAge(){
    return $this->iAge;
  }
 
  // Het commando dat de leeftijd van deze persoon zet
  public function setAge($iAge){
    if(!is_integer($iAge) || $iAge < 0){
      throw new Exception("Geen geldige leeftijd opgegeven");
    }
    $this->iAge = $iAge;
  }
 
}
?>

De class Person bevat in dit geval de eigenschappen Name en Age. Deze worden opgeslagen in een instantie van de class en zijn beide private. Het is daardoor onmogelijk om de waarden van buiten de instantie aan te passen:

<?php
$oPerson = new Person('Pietje');
echo $oPerson->sName;
?>

Dit zal de volgende foutmelding geven:

Fatal error: Cannot access private property Person::$sName in Person.php on line 2

Om toch de naam van een persoon op te vragen, kan je gebruik maken van de query getName:

<?php
$oPerson = new Person("Pietje");
echo $oPerson->getName();
?>

De reden dat de eigenschappen private zijn, is de verantwoordelijkheid die de class heeft. Deze class heeft de verantwoordelijkheid om ervoor te zorgen dat de naam van een persoon nooit zal wijzigen en dat de leeftijd altijd een geheel getal is. Een voorbeeld van deze laatste verantwoordelijkheid:

<?php
$oPerson = new Person('Pietje');
// Dit geeft een fatale fout
$oPerson->iAge = 30;
// Dit geeft een exception
$oPerson->setAge(-10);
// Dit werkt wel!
$oPerson->setAge(30);
?>

Doordat de eigenschappen vanaf buiten niet bereikbaar zijn, kan het setAge commando afdwingen dat alleen geldige waarden aan iAge toegekend worden.

Overerving

Overerving is een heel krachtig iets in OOP. Door overerving kan je alvast een basis van een class neerzetten zonder alles opnieuw te hoeven schrijven. Vaak is een overerving een specificatie van de bovenliggende class:

PHPFreak extends Person
Car extends Vehicle
HomeController extends Controller

In de subclass maak je meestal extra eigenschappen en methoden aan die alleen gelden voor die specificatie. Een voorbeeld hiervan is de class 'PHPFreak' die (uiteraard) overerft van de class Person:

<?php
class PHPFreak extends Person { 
  private $iPHPSkill;
 
  public function getPHPSkill(){
    return $this->iPHPSkill;
  }
 
  public function setPHPSkill($iPHPSkill){
    if(!is_integer($iPHPSkill)){
      throw new Exception("Geen geldig getal opgegeven");
    }
    $this->iPHPSkill = $iPHPSkill;
  }
}
?>

De class PHPFreak bevat dus dezelfde verantwoordelijkheden als Person, maar biedt ook een PHPSkill aan. De volgende dingen zijn bijvoorbeeld mogelijk:

<?php
// Maakt een nieuwe PHPFreak aan met naam 'Pietje'
$oFreak = new PHPFreak("Pietje");
// Bepaalt de leeftijd van deze PHPFreak
$oFreak->setAge(20);
// Zet de PHP skill van deze PHPFreak
$oFreak->setPHPSkill(100);
// Haalt de naam op
echo $oFreak->getName();
?>

Design by contract

Om je code uitwisselbaar te maken, is het verstandig om een contract bij je classes te leveren. Meestal staat dit contract in commentaar in je class. Een voorbeeld van de class Person met uitgebreide documentatie:

<?php
/**
 * Person class description
 */
class Person {
 
  private $sName;
  private $iAge;
 
  /**
   * Creates a new Person object
   * @param string $sName The name of the person
   */
  public function __construct($sName){ 
    $this->sName = $sName; 
  } 
 
  /**
   * Returns the name of this person
   * @return The name of this person
   */
  public function getName(){ 
    return $this->sName; 
  }
 
  /**
   * Returns the age of this person
   * @return The age of this person
   */
  public function getAge(){
    return $this->iAge;
  }
 
  /**
   * Sets the age of this person
   * @param integer $iAge The new age of this person, should be > 0
   */
  public function setAge($iAge){
    if(!is_integer($iAge) && $iAge > 0){
      throw new Exception("Geen geldige leeftijd opgegeven");
    }
    $this->iAge = $iAge;
  }
}
?>

Via een tool als PHPDocumentor kan dit commentaar uitgelezen worden. Iemand die jouw class wil gebruiken zal dan niet jouw complete code hoeven door te lezen, maar kan in één oogopslag zien wat jouw class te bieden heeft.

Dit verhaal werkt natuurlijk ook andersom: als jij een class van een ander wilt gebruiken, kan je meestal in de documentatie (ook wel API genoemd) terugvinden wat de class jou te bieden heeft. Om een simpel voorbeeld te nemen, de class PHPMailer zegt in zijn documentatie dat de class een methode 'AddAddress' heeft:

AddAddress (line 287)
 
Adds a "To" address.
void AddAddress (string $address, [string $name = ""])
 
    * string $address
    * string $name

Zonder te weten wat de inhoud van de method is, weet jij nu dat je via deze method een ontvangst adres aan je e-mail kan toevoegen:

<?php
$oPHPMailer = new PHPMailer();
$oPHPMailer->AddAddress('example@non-existing.org');
?>

In PHP5 kan je ook typehinten, waardoor je niet alleen in het commentaar kan laten zien hoe je methods werken. Dit is handig als we objecten in objecten gaan gebruiken. Hiermee kunnen we namelijk contracten tussen klassen maken, zodat ze met elkaar kunnen werken en op elkaar kunnen vertrouwen.

Als we nu een groep willen maken met personen, dan kunnen we gemakkelijk de eis stellen dat een persoon van het type Person moet zijn. Door gebruik te maken van typehinting weten we zeker dat we alleen Person objecten krijgen, waarvan we weten wat ze aan functionaliteiten bezitten (Eigenschappen) en wat we aan ze kunnen vragen (Queries).

Als een object een instantie is van een afgeleide klasse van Person (zoals bijv de PHPFreak klasse), dan bevat deze ook alle methods die we van Person kunnen verwachten en kunnen we die dus toestaan. Met deze gegevens in je achterhoofd kan je vervolgens interessante dingen doen:

<?php
class Group
{
	/**
	 * Groupmembers - Array of Person objects
	 * @var array
	 */
	private $aGroupMembers;
 
	/**
	 * Groupname
	 * @var string
	 */
	private $sGroupName;
 
	/**
	 * Create a new Group object
	 * 
	 * @param  string $sName
	 * @return void
	 */
	public function __construct( $sName )
	{
		$this->sGroupName = $sName;
	}
 
	/**
	 * Add a person to this group
	 * 
	 * @param  Person $oPerson
	 * @return void
	 */
	public function addPerson( Person $oPerson )
	{
		$this->aGroupMembers[] = $oPerson;
	}
 
	/**
	 * Return groupname
	 * 
	 * @return string
	 */
	public function getGroupName( )
	{
		return $this->sGroupName;
	}
 
	/**
	 * Return groupmembers
	 * 
	 * @return array of Person
	 */
	public function getGroupMembers( )
	{
		return $this->aGroupMembers;
	}
}
 
// nieuw persoon
$oJan = new Person( 'Jan' );
$oJan->setAge( 18 );
 
// nieuwe phpfreak
$oPiet = new PHPFreak( 'Piet' );
$oPiet->setAge( 21 );
$oPiet->setPHPSkill( 80 );
 
// nieuwe groep
$oGroup = new Group( 'Forum bezoekers' );
$oGroup->addPerson( $oJan );
$oGroup->addPerson( $oPiet );
 
// groep weergeven
echo 'In de groep "' . $oGroup->getGroupName() . '" zitten:<br />' . PHP_EOL;
 
foreach ( $oGroup->getGroupMembers() as $oPerson )
{
	echo $oPerson->getName() . '(' . $oPerson->getAge() . ')';
	if ( $oPerson instanceof PHPFreak )
	{
		echo ' die een echte PHPFreak is met skill ' . $oPerson->getPHPSkill();
	}
	echo '<br />' . PHP_EOL;
}
?>


Bron: Delen van deze pagina zijn afkomstig uit de presentatie 'Object Oriented Programming voor webapplicaties' door Edwin Vlieg

Zie ook: OOP Toepassen

Site Toolbox:

Persoonlijke hulpmiddelen
De laatste wijziging op deze pagina vond plaats op 4 apr 2009 15:29. - Deze pagina werd 5.993 maal bekeken. - Disclaimers - Over PFZWIKI