Gå til innhold

PHP·pub - Programming With Attitude - and beer


Anbefalte innlegg

Jeg prover meg litt med klasser.

 

I index.php deklarerer jeg $log

$log = new log_event();

 

sa trenger jeg a logge events i en av de andre klassene.

 

function __construct{)

{

global $log

}

 

men hvordan far jeg tak i funksjonene til $log fra en funksjon i den andre klassen?

Lenke til kommentar
Videoannonse
Annonse

For det første er det vanlig å begynne en klasse med stor bokstav, underscoreblir brukt bare for å separere pakkenavn fra klassenavn. For det andre ansees "global" for å være en dirty måte å gjøre det på. Gi det heller til konstruktøren. Her er mitt forslag:

 

class MyClass
{
//$log må være instans av LogEvent-klassen
public function __construct(LogEvent $log)
{
	 $this->log = $log;
}

}

 

Da må du initialisere klassen med $my_new_object = new MyClass($log);

 

Videre bruker du $this->log i metodene dine for å referere til loggobjektet.

Endret av dabear
Lenke til kommentar

Kan vel prøve å gi deg en kort forklaring.

 

Hele poenget med OOP er å representere verden i din kode, og med det så tenker man at diverse ting kan bli delt opp i klasser. Feks. så er mennesker en klasse. Dyr en annen. Et menneske er da et objekt av klassen mennesker (det samme med en dyr).

 

En klasse beskriver hvordan objekter av den klassen er, altså med egenskaper og funksjonalitet (properties, methods). Navnet på en klasse er som oftest et substantiv.

 

<?php
class Human {
public $name;
}

// lag et menneske (altså, et objekt av klassen human)
$etMenneske = new Human();
// $etMenneske er nå en peker til et Human objekt
// feks. for å sette navnet på mennesket
$etMenneske->name = "Homer";
?>

 

Det med subklasser, altså extends er sånn at hvis alt blir delt opp i klasser, så kan alt deles opp i sub-klasser. Altså alt er i et hieraki. Feks, så er Mann en sub-klasse av menneske. En dog en sub-klasse av animal, og hvis vi vil gå videre, en bulldog en subklasse av dog (som allerede er en subklasse av animal). Det siste eksemplet hadde sett sånn ut:

 

<?php

class Animal {
public $says = "hello";
}

class Dog extends Animal {
public $says = "bark";

public function bark() {
 echo "woof!";
}
}

class Bulldog extends Dog {
public $food = "beer";

public function bark() {
 echo "I am a bulldog!";
}
}
?>

<?php
$dyr = new Animal();
echo $dyr->says; // skriver "hello"

$hund = new Dog();
echo $hund->says; // skriver "bark"
$hund->bark(); // skriver "woof"

$bulldog = new Bulldog();
echo $bulldog->says; // skriver "bark"
echo $bulldog->food; // skriver "beer"
$bulldog->bark(); // skriver "I am a bulldog"

Når man definerer enda en variabel i en subklasse (som "says"-variablen i Dog klassen) så "overrider" den Animal sin "says" variabel. Dette kan du gjøre med metoder også (altså function definisjoner).

 

Når det gjelder interfaces så må man først kjenne til abstrakte klasser. En abstrakt klasse er en klasse som man ikke kan lage et objekt av. Feks. så kunne Animal klassen ha vært abstrakt (da hadde deklarasjonen vært abstract class Animal { ... ). Da kan man ikke lage objekter av den klassen ($dyr = new Animal() går ikke). Men andre klasser skal da utvide den med extend. Grunnen for dette er at et dyr er da ikke bare et dyr, men er da en spesifik type dyr. Et annet eksempel er feks. å ha en abstrakt klasse Menneske, som da har to subklasser Kvinne og Mann. Et menneske kan ikke bare være et menneske, et menneske må være enten Mann eller Kvinne, som da er subklasser av Menneske.

 

Hvis du har et objekt av Bulldog så er det en child av Dog, og Dog er en parent av Bulldog.

 

Hvis du la merke til "bark" metoden i Bulldog og "bark" metoden i Dog så la du sikkert merke til at de var deklarert på samme måte. Det vil si at "bark" metoden i Bulldog polymorfer "bark" metoden i Dog, altså den i Bulldog blir brukt når du lager et objekt av Bulldog, mens den "bark" metoden i Dog blir brukt når du lager et objekt av Dog klassen.

 

Et interface er en veldig abstrakt klasse som ikke burde følge hierakien. Klasser som implementerer et interface har en eller annen egenskap felles. Feks. så hadde både en Banana, Star og Giraffe implementert klassen Yellow siden de begge er gule, men de er jo ikke en felles parent. Et interface kan ikke ha noe innhold. Feks. et Yellow interface kanskje må ha en metode som sier hvilken farge det er (dårlig eksempel). Et typisk interface ser sånn ut:

<?php
interface Yellow {
public function color(); // alle klasser som implementer dette interfacet må polymorfe denne metoden (altså deklarer denne metoden) og den må være public (mer om det senere)
}

interface Spots {
// trenger ikke å ha noe i det hele tatt (det trenger ikke vanlige klasser heller)
}
?>

Og Banan og Giraffe hadde vært deklaret sånn:

<?php
class Banana implements Yellow {
public function color() {
 echo "A banana is yellow!";
}
}

// feks. 
class Giraffe extends Animal implements Yellow, Spots {
public function color() {
 echo "A giraffe is yellow with brown spots!";
}
}

// dette går ikke
class Star implements Yellow {
// ingen deklarasjon av color metoden
}

 

 

Nevnte også ordet public. Når du deklarer enten en variabel eller en metode som public så betyr det at alle har tilgang til det. Eks:

<?php
// extend og implement er unødvendig i dette eksemplet, men er der for å illustrere hieraki og tankemåte
class Cow extends Animal implements Spots {
public $name = "dolly";

public function milk() {
 echo $this->name." is being milked!"; // $this er en peker til seg selv, ellers får du ikke tak på $name
}

public function sleep() {
 echo $this->milk()." and is now tired!";
}
}

$ku = new Cow();
echo $ku->name; // 1
$ku->milk(); // 2
$ku->sleep(); // 3

Når alt er deklarert som public så fungerer både 1 2 og 3. Men dersom $name er deklarert som private så fungerer ikke nr. 1. En private deklarasjon betyr at bare et objekt av den klassen har lov å bruke den. Dersom milk() også hadde vært private så hadde ikke nr. 2 fungert, men nr. 3 fungerer forsatt. Men om du lager subklasser av Cow, feks en subklasse kalt Bambi (dårlig eksempel) så har ikke en metode i Bambi klassen tilgang til en metode eller variabel deklarert som private i Cow klassen. Private betyr privat for bare objekter av den klassen. Men dersom både $name og milk hadde vært deklarert som protected istedet så hadde metoder i Bambi tilgang til milk og $name.

 

Man har også et nøkkelord som heter final. Og man bruker det sånn:

<?php
class Human {
public final function help() {
 echo "F1! F1!";
}
}

class Man extends Human {
// ikke lov å polymorfe denne metoden siden den er deklarert som final i parent klassen Human.
public function help() {

}
}

 

Grunnen man har public, private, protected og final er for at man skal ha bedre kontroll over sikkerhet. Feks. i en database klasse er det ikke så gunstig å la passord være public for da kan andre objekter få tak på det, og endre det.

 

 

Håper det var litt klarere.

Lenke til kommentar

Tja, hvis du er ute etter litt «real world» eksempler på kan jo kanskje dette være noe:

 

Extend/arv

Extend er nyttig når du vil utvide funksjonaliteten i en klasse, men samtidig vil beholde den gamle. Et eksempel kan være at du bruker et rammeverk og ergrer deg over at f.eks user-klassen ikke støtter tilgangsrettigheter på den måten du ønsker. I stedet for å endre klassen fysisk (som vil gjøre det vanskelig å oppdatere seinere) kan du arve fra user-klassen og legge til det du trenger. I f.eks java brukes arv ekstremt mye til å arve fra komponenter osv. for å kunne utvide funksjonaliteten. I stedet for å lage en ny klasse som er «main»-klassen i applikasjonen med et JFrame-objekt inni arver man i stedet fra JFrame (hovedvinduet). Et annet eksempel (igjen fra java) er at man av og til trenger å overstyre toString-metoden (i f.eks JLabel) for å få ut noe vettugt i stedet for javax.swing.osv.

 

Interface

Interface gir ikke umiddelbart mye mening i PHP, men definerer et sett funksjoner klassene som implementerer dette trenger (tillegg kan man definerer felles konstanter). I typesterke språk må variabler være definert med en spesifikk datatype. Dvs. skal man lage en array må man si at det f.eks er en array av int-er og kan ikke si at den skal kunne inneholde int-er, float-er og tegn. Hovedgrunnen til å benytte seg av interface er derfor for å ha et sett funksjoner man kan bruke uten å vite hvilken klasse det er.

 

For å ta et eksempel: Hvis vi ser bort fra PDO et øyeblikk kan man bruke databaser som et eksempel. Vi har ørten forskjellige databaser vi kan bruke i PHP. Mysql, postgresql, mssql osv. Skal man lage noe som skal brukes på flere database-systemer trenger man noe felles. Uten interface, arv e.l må man i typesterke språk «hardkode» hva man jobber med. Hvis man derimot sier at «en database består av disse funksjonene» vil man kunne si at man jobber med en database uten å egentlig vite hva som er bak.

 

Hvis man ser litt på java igjen har vi ørten forskjellige komponenter. Det er veeeeeldig kjekt å kunne referere til de som JComponent i stedet for JLabel, JTextField, JTextArea osv. Det gjøre ting som lagring av de svært, svært enkelt (hvis man skal lagre en ubestemt sammensettning av de vel og merke). Altså man kan ha en array av JComponent i stedet for å ha en array med JLabel, en med JTextField, en med JTextArea osv.

 

Enda et eksempel på hvor nyttig dette er er vinduer. Tenk deg at du skal ha ørten vinduer inni en applikasjon av forskjellige typer. Det er veldig kjekt å kunne referere til de som vinduer uten å vite hva de egentlig er og samtidig vite at de har funksjoner for å hente ut tittel, sette størrelse, velge om det er synlige osv.

 

Abstrakte klasser

Motivasjonen for å bruke abstrakte klasser mer mye lik den for interface. Man trenger en felles måte å aksessere forskjellige klasser uten å vite hva det egentlig er man jobber med. Hvis man drar databaser litt videre kan man tenke seg at man vil cache resultater (siden det fort kan være flaskehalsen i en applikasjon). Det å cache et resultat må kunne sies å være rimelig likt uavhengig av databasen. Det eneste man trenger en dataene fra spørringen pluss litt info om hvilken spørring det er (ink. data i spørringen) i tillegg til en funksjon for å hente ut og/eller sjekke om det finnes cache for en gitt spørring. Dette kan såklart gjøres i en vanlig klasse, men da kan jo også lage et objekt av klassen, og det går jo ikke. I tillegg blir det litt problemer med å definere de felles funksjonene. Her kommer abstrakte klasser inn. Da kan vi hente funksjonene fra interfacet, definere det som abstrakt (altså at de må defineres i subklasser) og i tillegg definere funksjonene for caching.

 

 

Var det bedre tro?

 

 

PS: Ja, det ble litt mye java-relaterte greier her, men som sagt, det gir umiddelbart litt mer mening i et typesterkt språk hvor du rett og slett MÅ definere hva ting skal være og ikke kan ha en array bestående av «hummer og kanari» uten at de har noe felles.

Endret av Ernie
Lenke til kommentar

Jeg bruker en del abstrakte klasser og interface i et prosjekt jeg holder på med nå.

Det er flere ting som gjør at dette er hensiktsmessig:

  • For det første skal det være et bibliotek, og det er enklere å forholde seg til objekter, klasser og metoder enn masse løse variabler og funksjoner.
  • Selv om PHP ikke MÅ være et typesterkt språk, så støtter det noe som heter "type hinting" på mange områder. (Dvs. som parametere til funksjoner), noe som gjør at man kan "kreve" en egenskap/type.
  • Gjenbruk av kode. Dersom en gruppe med klasser skal ha samme "grunnfunksjonalitet" så kan det være greit å legge dette i en "baseklasse" som alle disse klassene arver. Dette gjøres allerede implisitt i PHP ved at alle toppklasser (dvs. at de ikke bruker "extends") som opprettes automatisk arver "stdClass" som har metoden __toString();

For meg er det første og siste punkt som er viktigst. Dvs at det er enklere for å meg å spre dokumentasjonen som et grenesnitt/API de kan forholde seg til. Dessuten har veldig mange av klassene mine mye av den samme funksjonaliteteten.

Lenke til kommentar

Når vi er innom klasser; har et "problem" her:

$foo = new Bar();
class fooBar{
function __construct(){
	$foo->set('bar');
}
}
$Barfoo = new fooBar();

Hvordan kan jeg bruke $foo inne i klassen fooBar? Er altså en klasse jeg vil skal være tilgjengelig overalt.

Endret av Rabbid
Lenke til kommentar

objekter blir overført ved referanse (altså de blir ikke kopiert), så det skal gå bra å gi den til klassen vha av konstruktøren. $Barfoo = new fooBar($foo) altså. Alternativet er en singleton pattern, feks:

 

http://www.developertutorials.com/tutorial...0729/page3.html

 

 

Wikipedia har faktisk et godt eksempel på singleton patterin i php:

 

http://en.wikipedia.org/wiki/Singleton_pattern#PHP_5

Endret av dabear
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...