Webbserverprogrammering02 [wesweb02]

Moment04 - Objektorientering

Introduktion

I detta moment skall vi kika på objektorientering inom PHP både genom att skapa egna klasser men framförallt för att bli duktigare att använda andras objekt. Vi märkte redan i förra momentet att det skapades objekt när vi jobbade med XML och då behöver vi förstå på ett djupare plan än att bara göra på ett visst sätt för att det skall vara så.

Momentets mål

I varje moment så jobbar vi mot ett eller flera mål som skolverket har satt upp i varje kurs.

Centralt innehåll

  • Webbserverns och dynamiska webbplatsers funktionalitet.
  • Utvecklingsprocessen för ett webbtekniskt projekt. Målsättningar, planering, systemering, kodning, optimering, dokumentation och uppföljning.
  • Dokumentation av utvecklingsprocess och färdig produkt, inklusive kod och mjukvarugränssnitt.
  • Funktionen i ett programmeringsspråk för dynamiska webbplatser.
  • Datalagring i relationsdatabas eller med annan teknik.
  • Datautbytesformat, till exempel XML (Extensive Markup Language) och JSON (Java Script Object Notation).
  • Teckenkodning. Begrepp, standarder och handhavande.
  • Kodning och dokumentation enligt vedertagen praxis för den teknik som används i sammanhanget.
  • Applikationsarkitektur och separation av olika slags logik.

Del 1 - Teori

Objektorientering är en viktig del av de objektorienterade programmeringsspråken. Det är ett sätt att försöka anpassa programmeringen mot den riktiga världen där helt andra datatyper finns än just de datatyper som finns inbyggt i programmeringsspråket. När vi skall sätta samman information om någon person eller en bil så räcker det inte att bara förlita sig på bara de enkla variabler som finns i en applikation. Det är då vi vill använda oss av objekt.

Om du har varit utsatt för objektorientering tidigare i något annat programmeringsspråk så kommer du märka att det i teorin inte är någon större skillnad, det som skiljer sig åt är hur vi skriver koden och möjligtvis små lokala skillnader. Jag kommer blanda den teoretiska biten med lite kodexempel som gäller för PHP. Har du redan koll på hur objektorientering fungerar så kommer du snabbt kunna översätta dina kunskaper, men vissa som läser denna kurs har inte läst Programmering 1 och har därför inte den teoretiska grunden att stå på. Teoridelen kommer jobba med en enkel klass som representerar en tärning. Genom uppbyggandet av denna klass kommer du få förståelsen för vad klasser, objekt och alla andra termer inom objektorienteringen betyder och hur de hänger ihop.

Klass

Vi börjar med klassen, det är den som är själva mallen för våra objekt. Klassen definierar vad som skall lagras om varje objekt. Om du ser klassen en som en pepparkaksform så förstår du att det är själva mallen/ramen för hur alla pepparkakor/objekt skall se ut, sedan hur varje pepparkaka/objekt ser ut påverkas av vad vi gör med den senare. Klassnamn brukar skrivas i singular och med första bokstaven som versal. Detta för att enkelt kunna skilja dem från andra delar av koden. Klassdefinitionen kan ligga i egen fil eller i samma fil som själva programmet. I exempelkoden nedan kommer jag lägga både klassen och programkoden i samma fil för att det skall vara enkelt att kopiera koden och testa lokalt.

<?php 
class Dice {
	
}
?>

Det enda som finns än så länge i vår klass är deklarationen som görs genom det reserverade ordet class samt klassens namn. Allt som hamnar mellan måsvingarna är det som klassen innehåller.

UML

UML

Vi ritar också ut klassens utseende i en bild, detta kallas UML-diagram (UML står för Unified Modeling Language) och är på samma sätt som att ha databasdiagram ett smidigt sätt att kunna visa upp hur klassen ser ut. Jag använder draw.io för att rita UML-diagrammen.

UML-diagrammet består av tre delar, den översta delen är namnet på klassen, den i mitten kommer innehålla medlemsvariabler och den sista raden innehåller medlemsfunktioner.

Medlemmar

En klass består av medlemmar, det är dessa som berättar något om hur klassen ser ut och vad klassen gör.

Medlemsvariabler

UML

Det första vi behöver specificera är klassens medlemsvariabler, här behöver vi ange ett namn och en synlighet. Vi kommer prata mer om synlighet senare med det är det lilla ordet som finns framför vår variabel (public i detta fall). Här skapar vi variabeln value som skall lagra värdet på en specifik tärning.

Om du tittar på UML-diagrammet så har det nu lagts till en rad med information om tre saker;

  • + - visar synligheten, vi återkommer till detta.
  • value - namnet på variabeln, denna skall följa dina andra variabelnamnsregler.
  • int - efter kolon skriver man vilken datatyp som variabeln har. Inom PHP så sker detta automatiskt men det är alltid bra att förstärka vad som lagras.
<?php 
class Dice {
	// medlemsvariabler
	public $value;		// Tärningens värde
	
}
?>

Medlemsfunktioner

UML

Funktioner som finns inne i en klass kallas för medlemsfunktioner eftersom den precis som en variabel är medlemmar av klassen, på det sättet är det enklare att hålla isär medelemsfunktioner och vanliga funktioner i PHP.

Medlemsfunktioner visas i tredje rutan i vårt UML-diagram, här hittar vi förutom funktionens namn och synlighet även ett ord efter kolon och detta anger vilken datatyp som returneras från funktionen. I vårt fall så anges void vilket innebär att ingenting returneras. Om det finns något som skall skickas in som argument till funktionen skall detta anges inne i parentesen med variabelnamn & datatyp, t.ex. setName(name:string).

Jag blandar lite vad man bör göra, rent generellt sett med fokus på UML, och vad som är brukligt i PHP. Eftersom vi i PHP inte anger datatyp så skulle vi kunna komma undan att inte heller göra det när vi dokumenterar PHP i UML, det viktigaste är att vi får med oss strukturen.

<?php 
class Dice {
	// medlemsvariabler
	public $value;		// Tärningens värde
	
	// Slumpar ett nytt värde på tärningen
	public function roll(){
		$this->value = rand(1,6);
	}
}
?>

Objekt

Jag har tidigare beskrivit att klassen är mallen och objektet är resultatet av klassen, jämförelsen med en pepparkaka och en pepparkaksform är faktiskt bättre än den först verkar. Varje nytt objekt är en exakt avbild av mallen, sedan bestämmer vi vilka värden våra variabler skall få.

new()

Varje objekt skapas genom nyckelordet new() som skapar en variabel som innehåller ett objekt av den klassen som används. Detta skall göras i programmets kod och inte inne i klassen.

<?php 
class Dice {
	// medlemsvariabler
	public $value;		// Tärningens värde
	
	// slumpar ett nytt värde på tärningen
	public function roll(){
		$this->value = rand(1,6);
	}
}
//	skapar ett nytt objekt av typen Dice
$d1 = new Dice();
?>

Variabeln $d1 innehåller just nu ett objekt av klassen tärning, den innehåller dock inget värde men det är möjligt att komma åt funktionen roll() eller medlemsvariabeln value.

Konstruktor

En konstruktor är en specialfunktion som körs när ett objekt skapas, och endast då. Om ingen konstruktor är skapad så skapas det temporärt en defaultkonstruktor som skapar ett tomt objekt. Om du själv skapar en konstruktor så kan det inte skapas en defaultkonstruktor. Men vi skapar en konstruktor som anropar funktionen roll() så att vår tärning får ett värde direkt då den skapas. För att från programkoden kunna nå en medlem i objektet så använder vi pilnotation som pekar från variabeln mot medlemmen.

<?php
class Dice{
	// medlemsvariabler
	public $value;		// Tärningens värde
	
	// konstruktor
	public function __construct(){
		$this->roll();
	}
	
	// slumpar ett nytt värde på tärningen
	public function roll(){
		$this->value = rand(1,6);
	}
}
// skapar ett nytt objekt av typen Dice
$d1 = new Dice();

// skriver ut tärningens värde
echo $d1->value;
?>

UML

Vi skapade en konstruktor och den kan vi välja att skriva upp i vårt UML-diagram om vi vill. I andra programmeringsspråk så är det inte ovanligt att skapa flera olika konstruktorer, det enda kravet är då att de skiljer sig i de parameterar som eventuellt skickas in till de olika konstruktorerna, att de är olika till antalet eller att de har olika datatyper. Inom PHP är det dock inte tillåtet att skapa flera olika konstruktorer.

Destruktor

På samma sätt som en konstruktor skapar ett objekt så finns det en destruktor som förstör objektet. Om vi inte skapar en egen destruktor så skapas det automatiskt en defaultdestruktor i samband med att PHP-motorn rensar upp bland variablerna, vi kan använda detta till att skriva ut att objektet tas bort. Detta är oftast inget vi vill skriva ut men ibland kan det vara intressant att logga om vi behöver felsöka någonting.

<?php
class Dice{
	// medlemsvariabler
	public $value;		// Tärningens värde
	
	// konstruktor
	public function __construct(){
		$this->roll();
	}
	
	// destruktor
	public function __destruct(){
		echo "<p>Objektet borttaget.</p>";
	}
	
	// slumpar ett nytt värde på tärningen
	public function roll(){
		$this->value = rand(1,6);
	}
}
// skapar ett nytt objekt av typen Dice
$d1 = new Dice();

// skriver ut tärningens värde
echo $d1->value;
?>

$this

Du har flera gånger sett variabeln $this inne i klassdeklarationen. $this handlar om att vi inne i objektet pratar med en specifik medlem, funktion eller variabel, i samma objekt. $this kan alltså bytas ut mot det egna objektet. Det verkar ju lite fånigt att vi måste specificera att det är vårt egna objekt vi jobbar mot men om vi jobbar med mer avancerade objektorientering så är det logiskt för då kommer vi in på arv vilket innebär att vi ibland pratar med vårt egna objekt, ibland pratar vi med en ärvd del av objektet eller helt enkelt objektets föräldrar.

Inkapsling (synlighet)

Inkapsling är en av de viktigaste principerna inom objektorientering. Som vår kod ser ut just nu så kan vi skriva koden $d1->value = 18; vilket skulle innebära att vår tärning fått värdet 18. Det är ju inte rimligt men vi har ingen säkerhet för att detta skall fungera. Det är då inkapsling och synlighet är viktigt. Vi kan välja att göra medlemsvariabeln $value osynlig utanför objektet genom att ge den värdet private. Då kommer vi endast åt variabeln genom objektets medlemsfunktioner, vi har redan en funktion roll() som tar hand om det slumpade värdet men vi måste skapa en ny funktion som kan hämta värdet åt oss. För i samma sekund som medlemsvariabeln $value får synligheten satt till private så kommer vi inte kunna skriva ut den längst ner i vår programkod.

<?php
class Dice{
	// medlemsvariabler
	public $value;		// Tärningens värde
	
	// konstruktor
	public function __construct(){
		$this->roll();
	}
	
	// destruktor
	public function __destruct(){
		echo "<p>Objektet borttaget.</p>";
	}
	
	// slumpar ett nytt värde på tärningen
	public function roll(){
		$this->value = rand(1,6);
	}
}
// skapar ett nytt objekt av typen Dice
$d1 = new Dice();

// skriver ut tärningens värde
echo $d1->value;
?>
UML

jag har ändrat synligheten på medlemsvariabeln, skapat funktionen print() och anropat denna från programkoden. Jag väljer att låta variabeln returneras så att jag själv bestämmer hur den skall skrivas ut. Att bara returnera en variabel utan att förändra den brukar ibland kallas att vi har skapat en get_funktion (en getter), vi hämtar alltså värdet, på detta sättet brukar man skapa getters och setters för alla medlemsvariabler för att kunna kommunicera med variabeln. Exakt hur detta görs kan skilja sig mellan olika programmeringsspråk.

Eftersom vi har ändrat i klassen så måste vi ändra vårt UML-diagram. Lägg märke till hur plustecknet (+) framför medlemsvariabeln value ändrades till ett minustecken (-), det är så vi tydliggör att synligheten nu är satt till private. Det finns en vanlig synlighet som vi inte har pratat om och det är protected. Protected har med arv att göra, vilket vi inte tar upp i detta moment.

Objektorientering fördjupning

Då har vi gått igenom grunden i objektorientering och precis som jag skrivit tidigare så är detta inget försök att göra en komplett genomgång av tekniken. Det viktigaste är att du får med dig grunderna så att du förstår hur det fungerar när vi fortsättningen kommer råka ut för objekt i olika tillfällen.

Tycker du att det verkar kul och vill vidareutvecklas inom områdetså rekommenderar jag kom igång med oophp på 20 steg från dbwebb.se eller rätt in på manualen för klasser och objekt på php.net.

Del 2 - Praktisk användning genom tutorial

Vi kommer jobba vidare med contact03 och bygga på den så att våra kontakter läses in som objekt från databasen. Denna tutorial når du här.

Redovisning

Lägg upp dina applikationer på din webbplats, skriv en samlad utvärdering av de olika applikationerna på din wordpressida.