Reactie plaatsen 
 
Waardering:
  • 1 stemmen - gemiddelde waardering is 5
  • 1
  • 2
  • 3
  • 4
  • 5
OOP Singleton class
Auteur Bericht
X5 Offline
Member
***

Berichten: 106
Lid sinds: 10-2007
Reputatie: 0
Bericht: #1
OOP Singleton class
Hoi,

ik wil graag een bijdrage doen dus bij deze een tutorial/techniek om singleton classen makkelijk te beheren

Inhoud
  1. Intro
  2. Directory structuur indelen
  3. De interface bepalen van onze class
  4. De Singleton class schrijven
  5. De CurrentUser class schrijven, de class die een Singleton is
  6. De User class schrijven
  7. Testen!



1. Intro
Je zult wel al moeten weten hoe je met objecten werkt.
Gelukkig is PHP makkelijk dus alsnog interessant/goed te doen voor beginners om dit door te lezen

Ik zal steeds de code die ik laat zien toelichten maar het commentaar en uitleg zal vooral in de code zelf staan!

2. Directory structuur indelen
De directory structuur komt er zo uit te zien:

- classes
---- CurrentUser.php
---- Singleton.php
---- User.php
-- interfaces
---- ISingleton.php
- index.php

Maak deze aan, laat de bestanden even leeg die gaan we zo invullen :-)

3. De interface bepalen van onze class

Een interface kun je zien als een omschrijving van de mogelijkheden van een class die deze interface implementeerd.
Neem bijv. een afstandbediening, iedere afstandsbediening heeft ongeveer deze interface (pseudo):

- Inschakelen
- Uitschakelen
- Volgende zender
- Vorige zender
- Volume harder
- Volume zachter

We weten nu precies wat voor mogelijkheden we hebben maar we hebben geen idee HOE de afstandsbediening dit uitvoert maar we weten wel welke functionaliteit we hebben, bij deze een stukje code om de interface van de Singleton class te bepalen:

PHP-code:
<?php

interface ISingleton
{
    
/**
     * Retourneert instance van onze Singleton
     *
     * @return ISingleton
     */
    
static function getInstance();


Dus wat we nu hebben is dat de classen die de interface ISingleton implementeren de mogelijkheid hebben om een instantie op te vragen van de class.
Nu gaan we het makkelijk maken voor onszelf door een basis class te schrijven die dit voor ons doet en wij niks hoeven te doen, bijna niks dan.

Om even terug te komen op het afstandsbediening verhaal, wij gaan nu dus de Sony afstandsbediening maken en niet de bijv. Samsung afstandsbediening, volgende deel ga ik laten zien hoe Sony dit oplost.

3. De Singleton class schrijven

PHP-code:
<?php
// Singleton pattern class
// Deze is abstract, dit betekent dat deze class MOET ge-extend worden 
// en kan nooit voorkomen dat deze code word uitgevoerd:
// $obj = new Singleton(), dit word een error dus.
abstract class Singleton 
implements ISingleton
{
    
    
/**
     * De ingeladen instanties
     * hier zullen onze instanties inkomen en beheerd worden
     * 
     * @var ArrayObject
     */
    
private static $instances;
    
    
/**
     * Deze propertie houd bij of we zijn geinitialiseerd, zie: _staticInitialized()
     *
     * @var boolean
     */
    
private static $initialized;
    
    
/**
     * Dit is de constructor, deze defineren we alleen om ervoor te 
     * zorgen dat de subclass nooit zal worden geinitialiseerd met new ...()
     * Dit heet het Singleton design pattern
     */
    
protected function __construct()
    {
    }
    
    
/**
     * Deze functie initialiseerd onszelf, dit kan je zien als een 
     * constructor alleen dan statisch
     * 
     * @return void
     */
    
private static function _staticInitialize()
    {
        if( 
self::$initialized === false )
        {
            
// initialiseer onze instances 
            
self::$instances = new ArrayObject();
            
            
// we zijn geinitialiseerd, dit zorgt ervoor dat als deze 
                        // functie meer dan 1x word aangeroepen dat de 
                        // instances niet gereset word
            
self::$initialized true;
        }    
    }
    
    
/**
     * Retourneert de instantie van de opgegeven class naam 
     *
     * @param string $className
     * @return ISingleton
     */
    
protected static function _getInstance($className)
    {
        
// initialiseer onszelf indien nodig, deze check word in _staticInitialize() gedaan
        
self::_staticInitialize();
        
        
// check of de opgegeven class niet al eens is geinitialiseerd
        
if( self::$instances->offsetExists($className) === false )
        {
            
// de class is nog niet eerder geinitialiseerd, initialiseer deze nu
            
self::$instances->offsetSet($className, new $className);
        }
        
        
// vanaf dit punt weten we zeker dat de class is ingeladen 
                // tenzij er een error is opgetreden, deze check laat ik nu even achterwege
        
return self::$instances->offsetGet($className);
    }


Deze class is nu onze Sony afstandsbediening, zoals je ziet implementeert deze de class ISingleton, normaal zou deze class nu verplicht zijn
om de functie getInstance() te implementeren maar omdat deze abstract is word ervoor gezorgt dat de subclass deze moet implementeren.
Dit is nodig omdat de class Singleton niet de naam kan opvragen van de class die Singleton extend (de subclass dus)
Dit is best jammer omdat je nu in iedere class getInstance() moet implementeren.
Verder is het nu vrij simpel, in het volgende hoofdstuk laat ik zien hoe we de CurrentUser gaan maken want we hebben ALTIJD maar 1 currentUser
je hebt nooit meer dan 1 actieve gebruiker, daarom is dit dus een Singleton.
Als het idee van het singleton patroon nog niet duidelijk is kun je het melden dan zal ik een betere uitleg proberen te geven mits je goed omschrijft wat je niet begrijpt.

4. De CurrentUser class schrijven, de class die een Singleton is

De CurrentUser is dus een Singleton en we hebben geen zin om elke keer de instance te beheren dus gaan we de functionaliteit van Singleton gebruiken
en uitbreiden met onze eigen class: CurrentUser
Dit is een vrij simpele class, ik zal zo toelichting geven over de getInstance() methode:

PHP-code:
<?php

// Houd de huidige gebruiker bij, je kunt via CurrentUser::getInstance()->user()->username() bijv de gebruikersnaam opvragen
// Nu is het bijv ook mogelijk om het korter te maken shortcut functies
// te maken in deze class maar dat moet je zelf weten
// hierdoor is het wel zo dat je wellicht dubbele code krijgt.
class CurrentUser 
extends Singleton 
// extenden zodat deze class alle functionaliteit krijgt van de class 
// Singleton + functionaliteit die in deze class zelf word geschreven
{
    
/**
     * De gebruiker instantie
     *
     * @var User
     */
    
private $user;
    
    protected function 
__construct()
    {
        
// laat de Singleton ook zichzelf "constructen"
        
parent::__construct();
        
        
// initialiseer de Gast als standaard gebruiker
        
$user = new User();
        
$user->hasIdentity(false);
        
$user->username('Gast');
        
        
// gast instellen
        
$this->user $user;
    }
    
    
/**
     * Retourneert de instantie van deze class
     * Herinner de functie uit de ISingleton interface nog? 
     * Hier word die nu geimplementeerd
     * Dit laat de parent, de parent is in dit geval de class Singleton en
     * laat die een instantie van deze class ophalen of aanmaken.
     * Omdat we nu in een "static function" zitten is er dus nog GEEN 
     * instantie aangemaakt van deze class!
     *
     * Voor de gevorderde phpers, misschien hebben jullie hier een 
     * antwoord op:
     * Het is jammer dat deze functie hierin moet maar vanuit de 
     * Singleton class kan je in PHP op 1 of andere manier niet de 
     * classname opvragen van de subclass
     * In die geval dus CurrentUser maar Singleton kan daar niet 
     * bijkomen, vandaar deze "hack"
     * 
     * @return CurrentUser
     */
    
public static function getInstance()
    {
        return 
parent::_getInstance(__CLASS__); 
                
// __CLASS__ retourneert de classnaam van zichzelf
    
}
    
    
/**
     * Deze functie is een setter/getter in 1, als er een User word 
     * meegegeven in de parameters dan zal deze worden gezet, anders niet
     * bovendien word er ALTIJD een User object teruggegeven, een 
     * Guest is tenslotte ook een user maar zonder identiteit.
     * 
     * @param User $user
     * @return User
     */
    
public function user(User $user=null)
    {
        if( 
$user !== null )
            
$this->user $user;
            
        return 
$this->user;
    }


Check commentaar voor uitleg.

5. De User class schrijven
Dit is een class die gegevens van een gebruiker bevat zoals de username en identiteit check (tot nu toe, later zou je dit natuurlijk kunnen uitbreiden met een email, password, voornaam, achternaam noem het maar op)
Hier zeg ik niet veel over, dit is een zeer simpele class, lijkt me duidelijk zat, alsnog wel overal commentaar toegevoegd.

PHP-code:
<?php

// deze class is nu heel erg simpel maar deze kan natuurlijk zo uitgebreid worden als je zelf wil!
class User
{
    
/**
     * De gebruikersnaam
     *
     * @var string
     */
    
private $username;
    
    
/**
     * Als deze variable op true staat betekent dit dat de gebruiker is ingelogd
     *
     * @var boolean
     */
    
private $hasIdentity;
    
    
// Initialisatie
    
public function __construct()
    {
        
$this->hasIdentity false;
    }
    
    
/**
     * Sets/gets de gebruikersnaam
     *
     * @param string $value
     * @return string
     */
    
public function username($value=null)
    {
        if( 
$value !== null )
            
$this->username $value;
            
        return 
$this->username;
    }
    
    
/**
     * Retourneert of de gebruiker een identiteit heeft, zoja, dan is 
     * deze als ingelogd "gaflagged"
     *
     * @param boolean $value
     * @return boolean
     */
    
public function hasIdentity($value=null)
    {
        if( 
$value !== null )
            
$this->hasIdentity = (boolean)$value
// (bool) "cast" de waarde ($value) om naar een boolean zo weten we 
// altijd zeker dat we een boolean terug krijgen
        
        
return $this->hasIdentity;
    }

Lijkt me duidelijk. En dan nu eindelijk, testen! ^^

6. Testen!
Plaats in je index.php:

PHP-code:
<?php
// start de sessie
session_start();

// zet error reporting aan
error_reporting(E_ALL);

// include onze interfaces
require_once 'interfaces/ISingleton.php';

// include onze classen
require_once 'classes/Singleton.php';
require_once 
'classes/User.php';
require_once 
'classes/CurrentUser.php';

// Probeer onze class uit!
$currentUser CurrentUser::getInstance()->user();

// We hebben nu nog geen gebruiker toegekend die de currentUser zou
// zijn dus als we nu de username gaan uitprinten krijgen we Gast te zien:
echo 'currentUser[username]: ' $currentUser->username() . '<br />' PHP_EOL;

// Dit werkt, nu gaan we een user aanmaken, deze zou normaal 
// gesproken uit de sessie komen, dan checken in database,
// gegevens ophalen en dan de user invullen op basis van database 
// gegevens, nu doen we het even hard coded, database
// tutorials komen later wel ^^
$user = new User();
$user->hasIdentity(true);
$user->username('X5');

// stel deze gebruiker in als ingelogde gebruiker
$currentUser CurrentUser::getInstance()->user($user);

// laten we nogmaals de gebruikersnaam weergeven:
echo 'currentUser[username]: ' $currentUser->username();

// voila!
// Mijn output was:
/*
currentUser[username]: Gast
currentUser[username]: X5
*/

// een testje om te laten zien dat CurrentUser maar 1x aangemaakt mag worden:
// uncomment de volgende regel uit om het te zien, dan zul je de fout 
// zien en kan je deze later terugherkennen als je deze techniek toeapast
//$user = new CurrentUser(); 

Er staat veel commentaar in, indien niet duidelijk hoor ik het graag.
Alle classnamen komen overeen met hun bestandsnaam!

Greetings,

X5.
(Dit bericht is het laatst bewerkt op 26-12-2009 om 21:32:58 door Jasper.)
26-12-2009 19:57:01
Alle berichten van deze gebruiker zoeken Reageren op dit bericht
Jasper Offline
Ep2 Admin
******

Berichten: 15.056
Lid sinds: 04-2006
Reputatie: 223
Bericht: #2
RE: OOP Singleton class
Ik ben geen ervaren OOP coder, dus van mij uit de vraag... Wat is "singleton"?

Wel een mooie tut denk ik verder, iig erg bedankt voor het plaatsen ervan!! Ik heb eea aan enters geplaatst, zodat de forumlayout gewaarborgd blijft. Hope you don't mind!

Om de zeven minuten denkt de vrouw dat de man alleen maar aan seks denkt.
(Dit bericht is het laatst bewerkt op 26-12-2009 om 21:33:39 door Jasper.)
26-12-2009 21:29:45
De website van deze gebruiker bezoeken Alle berichten van deze gebruiker zoeken Reageren op dit bericht
X5 Offline
Member
***

Berichten: 106
Lid sinds: 10-2007
Reputatie: 0
Bericht: #3
RE: OOP Singleton class
(26-12-2009 21:29:45)Jasper schreef:  Ik ben geen ervaren OOP coder, dus van mij uit de vraag... Wat is "singleton"?

Wel een mooie tut denk ik verder, iig erg bedankt voor het plaatsen ervan!! Ik heb eea aan enters geplaatst, zodat de forumlayout gewaarborgd blijft. Hope you don't mind!

Sorry was even vergeten erbij te zeggen dat het voor het publiek bedoeld was dat al ervaring had met OOP.
Een singleton is niks meer dan een design pattern dat ervoor zorgt dat er altijd maar 1 instantie van een object bestaat. Je hebt bijv. x aantal users iedere user zou een User object zijn, dit is dus GEEN singleton, maar stel dat er zoals in mijn voorbeeld een class zou zijn die de huidig ingelogde gebruiker voorstelt dan is het WEL een singleton want er is altijd maar 1 active gebruiker (per sessie/request natuurlijk).

Hoop dat het duidelijk is :-)
26-12-2009 22:52:23
Alle berichten van deze gebruiker zoeken Reageren op dit bericht
Reactie plaatsen 


Ga naar locatie:


Contact opnemen | Ep2 | Naar boven | Naar inhoud | Archiefmodus | RSS-syndicatie