Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  7 6783
Sur og sarkastisk
droppboks's Avatar
Så du har lyst å lære om klasser i PHP? Kanskje du har googlet litt og fortsatt ikke forstår bæret?
I så fall er du der jeg var når jeg leste den korte innføringen til klasser i "Webprogrammering i PHP".
Det er en god bok og sånn, men jeg syntes innføringen til klasser var forvirrende, så jeg skal prøve å
forklare det på en bedre måte. Ingen bilklasser! Lover!

En klasse er egentlig en samling variabler og funksjoner som jobber med hverandre i et lukket miljø, en
har kun tilgang til enkelte funksjoner og variabler (programmerer bestemmer hvilke, kommer tilbake til det).
Hva er vitsen med DET? Spør du sikkert, eller kanskje ikke, kanskje du allerede har forstått det, hvis ikke
så kommer jeg til det nå.

Fordelen her er for det første at koden ser ryddigere ut, og er enklere å vedlikeholde, det andre er at om
flere koder sammen på noe, så kan de jobbe uavhengig av hverandre, men nok prat, er det noe du lurer på så
bare spør.

Nå kommer vi til kodingen, tenkte vi skulle fokusere på en enkel MySQL-klasse, noe konkret og
relevant til koding.

I PHP så lager du en klasse slik:

Kode

<?php
class sqlBehandler { // Hva du vil som navn (stort sett) og startparentes
} // Sluttparentes
?>
Sånn! Du har akkurat laget din første klasse, nå, la meg introdusere dere for noen begreper.

Når du legger til variabler eller funksjoner inni en klasse i PHP, så bruker du disse begrepene:

Kode

<?php
public // Dette blir tilgjengelig utenfor objektet (et objekt er en initialisert klasse, dvs, når du faktisk bruker klassen
private // Dette blir KUN tilgjengelig innenfor denne klassen.
protected // Dette blir tilgjengelig innenfor denne klassen, og eventuelle child-classes (vil ikke dekke temaet i denne guiden)
?>
Disse ordene legges før en variabeldefinisjon eller en funksjonsdefinisjon.

Okei, nok om det, la oss gå over til å faktisk legge noe fornuftig inni klassen vår.

Kode

<?php
class sqlBehandler {
	// for enkelhets skyld definerer vi MySQL-infoen som variabler inne i klassen.
	private $user	=	'user'; 
	private $pw		=	'pass';
	private $host	=	'localhost';
	private $db		=	'testDb';
	protected $con;		// Inni her legger vi resource til connection etterhvert, utvidelser (child classes) av klassen burde ha tilgang til denne, derfor protected
	
	public function connect() { // definerer en funksjon som vanlig, med untaket at vi setter "public" foran.
		$this->con	=	mysql_connect($this->host, $this->user, $this->pass) or die('Feil i tilkobling: '.mysql_error());
		mysql_select_db($this->db) or die('Kunne ikke koble til database: '.mysql_error());
	} // slutt på connect
} // slutt på sqlBehandler
	?>
Okei, som vi ser her definerer vi variabler og funksjoner akkurat som vi ville gjort "utenfor" en klasse,
med unntak av ordet foran. Men vent nå, burde ikke jeg forklare hva jeg gjorde inni connect-funksjonen?
Jo, som dere ser brukte jeg ordet $this-> foran variabelnavnene, dette er fordi at hvis ting i klassen
skal samarbeide, må de kjenne igjen ting "utenfor" funksjonen, derfor brukes "this", så klassen vet
"denne klassen, i dette objektet", du venner deg nok til det.

Okei, sånn definerer vi altså en klasse, men hvordan bruker vi den da? Jo, det er ganske enkelt, du går
inn i PHP-filen med klassen, eller en PHP-fil som har filen med klassen inkludert, og gjør dette:

Kode

<?php
	$sql	=	new sqlBehandler; // new forteller PHP at du skal bruke klassen, og du vil legge denne instansen i variabelen $sql, $sql blir da et såkalt "objekt"
	// For å bruke connectfunksjonen gjør vi dette:
	$sql->connect(); 
?>
Nå har vi et objekt, men det gjør egentlig ingenting, simpelthen kobler til MySQL inne i objektet (en versjon av denne klassen).
La oss utvide med en funksjon til, legg til dette under connect:

Kode

<?php
	// Denne funksjonen skal kjøre spørringer mot databasen. 
	public function query($query) {
		$query	=	mysql_real_escape_string($query); // Sikrer mot SQL-injections.
		$query	=	mysql_query($query, $this->con) or die("Feil i spørring: ".mysql_error());
		return $query; // returnerer spørringen.
	}
?>
Ettersom denne også er public, kan du få tilgang til denne også via objektet du lagde over her, den vil simpelthen kjøre
spørringen du skriver inn i query.

Kode

<?php
// Denne vil automatisk sikre mot SQL-injections og håndtere errors
$sql->query("SELECT * FROM nobraindk WHERE meatspin='.com'");
?>
Dette var en noe kort guide, men jeg visste ikke hva mer heelt basic jeg kunne skrive om, jeg har ikke tatt for meg disse
temaene, som du kanskje kan se på videre:

Magic Methods, Statiske klasser (static), abstrakte klasser, arv (parent og child klasser), og sikkert mer jeg har glemt.

Respons er alltid fint Negativ eller positiv, hva kunne jeg gjort annerledes i guiden? Suger jeg på å lære bort ting? Osv.


- Choobe

Okei, jeg skal skrive litt om magic methods og arv ettersom jeg kjeder meg for øyeblikket.

Jeg blir ikke å dekke alle magic methods, kun de jeg bruker ofte, og ser på som mest nyttige.

Først, PHP reserverer alle funksjoner som starter med "__" (2 underscore) som "Magic Methods", så det er anbefalt å ikke bruke
det i starten av en funksjon hvis du ikke skal bruke noe med dokumentert "magisk" effekt (dette er det PHP.net sier).

Først, skal vi se på __construct og __destuct. Dette er funksjoner som blir kjørt når et objekt lages eller unsettes. La oss
gå inn i klassen vår, rett under alle variablene å sette inn dette:

Kode

<?php
public function __constuct() { // magic method, denne blir kalt med en gang du initialiserer klassen (dvs: lager et objekt)
	mysql_select_db($this->db, $this->connect()) or die('Feil, kunne ikke koble til database: '.mysql_error()); // velger database
} ?>
Og siden vi gjør det på den måten, må vi nesten endre litt på funksjonen connect oppi her, samtidig fjerner vi bare variabelen $con:

Kode

<?php
protected function connect() { 
	// Returnerer mysql_connect
	return mysql_connect($this->host, $this->user, $this->pw) or die('Kunne ikke koble til MySQL: '.mysql_error());
} ?>
Ettersom vi gjorde det slik, så må vi også endre på funksjonen "query", beklager, dårlig planlagt fra min side.

Kode

<?php
public function query($query)  { // 
	$query	=	mysql_real_escape_string($query); // Sikrer fortsatt mot sql-injections.
	// Her returnerer vi den direkte, i stedet for å ha en unødvendig linje hvor vi setter $query til en mysql_query
	return mysql_query($query, $this->connect()) or die('Feil i mysql-spørring: '.mysql_error());
?>
Sånn, da ordnet vi opp i det. Nå skal vi legge til en "__destuct" funksjon, som basicly kjører når du bruker 'unset' på objektet,
eller at skriptet blir ferdig å kjøre, vanligvis håndterer PHP mysql_close av seg selv, men det er god skikk å avslutte likevel.

Kode

<?php
public function __destuct() {
	mysql_close($this->connect()) or die('Kunne ikke avslutte MySQL: '.mysql_error());
} ?>
Sånn, det burde dekke det.

Nå skal vi se litt på arv, for vi skal nemlig lage en klasse for å behandle MySQL arrays, vi begynner med å lage klassen.

Kode

<?php
class sqlArray extends sqlBehandler { // extends betyr at den arver alle protected og public funksjoner fra parent-klassen (sqlBehandler)
	private $_array; // Arrayet vårt blir satt inni denne når det er laget. Setter en underscore foran, da array er en funksjon i php.
	private $_table; // For å få ha tabellnavnet i senere. Underscore så man har et mønster i variablene.
	
	public function __constuct($query) { // denne constructen tar et argument, demonstrasjon av bruk senere
		parent::__construct(); // så vi får databasen, bruker parent for å få tilgang til foreldreklassens funksjoner.
		
		// Standardprosedyre.
		 $query	=	mysql_real_escape_string($query);
		 $query	=	mysql_query($query, parent:connect()) or die('Feil i spørring: '.mysql_error());
		 
		// Lager arrayet.
		$this->_array	=	mysql_fetch_assoc($query) or die('Feil, kunne ikke lage array: '.mysql_error());	
		// Henter ut tabellen, denne skal vi bruke senere.
		$this->_table	=	mysql_field_table($query, 1) or die('Feil, kunne ikke hente ut tabell: '.mysql_error());
	}
} ?>
Med meg så langt? Okei, nå skal jeg vise dere hvordan man lager dette fantastiske objektet med argumenter på __constuct.

Kode

<?php
	$arr	=	new sqlArray('SELECT * FROM nobraindk WHERE meatspin=\'.com\'');
?>
Kult hæh? Men ganske unyttig foreløbig. Som bringer oss til neste steg, nemlig magic methodene __get og __set.
__get gjør at du kan få tak i data, __set gjør at du kan sette data, suger litt på å forklare dette, la meg heller
demonstrere:

Kode

<?php
	public function __get($var) { // __get tar ET argument.
		return $_array[$var]; // Vi returnerer MySQL-dataen som vi la i arrayet i __construct.
} ?>
Dette gjør at vi kan få tak i dataen via objektet slik:

Kode

<?php
// Tar i bruk __get
echo $arr->meatspin; // vil skrive ut ".com".
?>
Neste er __set, om den skal fungere på måten jeg tenker på så må vi gjøre ting litt avansert.

Kode

<?php

	public function __set($var, $value) { // __set tar TO argumenter, det første er variabelen, det andre er verdien den settes til.
		
		// Få tak i den gamle verdien.
		$old	=	$this->__get($var);
		
		// Oppdatere mysql_data.
		mysql_query("UPDATE {$this->table} SET {$var}='{$value'} WHERE {$var}='{$old}'", parent::connect()) or die('Feil, kunne ikke oppdatere',$var,': ',mysql_error());
		
		// Oppdatere arrayet vårt.
		$this->_array[$var] = $value;
	}
?>
Hvordan bruke denne spør du? Jo slik:

Kode

<?php
	// Tar i bruk __set
	$arr->meatspin = '.no';
?>
Det var alt for denne gang, to andre nyttige magic methods kan være __invoke og __toString, men jeg fant ikke nytte for dem i denne
klassen, kanskje dere kan se på det selv?

- Choobe
▼ ... noen måneder senere ... ▼
God dag min gode venn.
Jeg googlet disse to funksjonene (__invoke og __toString) og trur jeg vet hva toString gjør, men sliter litt med å forstå invoke, så om noen hadde forklart så hadde jeg blitt teaknemlig
Sur og sarkastisk
droppboks's Avatar
Trådstarter
Sitat av KaiN Vis innlegg
God dag min gode venn.
Jeg googlet disse to funksjonene (__invoke og __toString) og trur jeg vet hva toString gjør, men sliter litt med å forstå invoke, så om noen hadde forklart så hadde jeg blitt teaknemlig
Vis hele sitatet...
Ja, disse to funksjonene gjør henholdsvis at du kan behandle klassen som en "string" eller en funksjon, du sier du tror du forstår __toString, men legger ved en kort forklaring likevel:
__toString er en "magic method" som blir brukt hvis du prøver å bruke objektet du lagde som en string, ved og f. eks skrive den ut på skjermen.

Syntaxen er vel omtrent slik:

Kode

public function __toString() {
// her inne kan du ha en return-funksjon som returnerer en string fra klassen.
// kan være nyttig hvis du vil lage din egen string-klasse, strings behandles
// såvidt jeg vet ikke som objekter i PHP. 
}
Den andre, __invoke, er det som skjer hvis du prøver å bruke objektet som en funksjon, hvis du lager en klasse for filbehandling, og vil lese inn en ny fil, kan du bruke:

Kode

public function __invoke($filename) {
 // Hva du vil gjøre med filen
}

//Kalle på __invoke på objektet $fil
$fil('mygaypornlist.txt');
Det er et litt dårlig eksempel, men håper du/dere tar poenget.
▼ ... noen måneder senere ... ▼
Sur og sarkastisk
droppboks's Avatar
Trådstarter
Jeg har blitt gjort oppmerksom på at jeg har skrivefeil i guiden, det skal selvsagt være __constRuct og __destRuct (uten stor R da)... i tillegg er visst mysql_funksjoner utdatert, dere burde bruke mysqli eller PDO eller noe...
Ikke noe fan av die, men ok.

Syns du kan skrive hvordan du kan chaine også, ettersom det er ekstremt nyttig i ting som f.eks en database-klasse

Kode

<?php

class Database
{
    
    public function select($args)
    {
        // ... 
        return $this
    }
    
}

?>
Hva med statiske metoder og klassevariabler?
Sur og sarkastisk
droppboks's Avatar
Trådstarter
Klassevariabler har jeg jo med i en av de første kodesnuttene?

Chaining og statiske metoder har jeg ikke vært noe særlig borti, har liksom aldri fått bruk for det (i hvert fall ikke enda), så jeg er ikke helt opplest på det, men hvis du (eller noen andre for det saks skyld) får lyst å skrive litt om det så feel free til å gjøre det.
▼ ... noen måneder senere ... ▼
Sitat av hayer Vis innlegg
Ikke noe fan av die, men ok.

Syns du kan skrive hvordan du kan chaine også, ettersom det er ekstremt nyttig i ting som f.eks en database-klasse

Kode

<?php

class Database
{
    
    public function select($args)
    {
        // ... 
        return $this
    }
    
}

?>
Hva med statiske metoder og klassevariabler?
Vis hele sitatet...
[quote=hayer;2831651]Ikke noe fan av die, men ok.

Syns du kan skrive hvordan du kan chaine også, ettersom det er ekstremt nyttig i ting som f.eks en database-klasse

Kode

<?php

class Database
{
    
    public function select($args)
    {
        // ... 
        return $this
    }
    
}

?>
Hva med statiske metoder og klassevariabler?
▼ ... over en uke senere ... ▼
z0p
uʍop ǝpısdn
z0p's Avatar
Grei gjennomgang, men den utmerker seg ikke spesielt fra andre enkle introduksjoner til php / generell OOP.
Det å skulle både gi en innføring i generell OOP samtidig som man skulle forklare idiomer i et språk som PHP, er å påta seg en stor oppgave.

Personlig hadde jeg nok heller satt pris på en innføring i OOP PHP idiomer. Detaljer rundt styrker og svakheter i PHPs objektmodell, hvordan PHP håndterer klassehierarkier, instanser, inheritance. Peke på særegenheter i PHPs objektmodell, og kanskje vise noen de facto standard på typiske OOP løsninger i PHP.
I det hele tatt kun fokusere på PHP-spesifikke detaljer.

OOP innføringer finnes det i massevis av fra før. Problemet er vel at mye av dette skrives av personer som er tidlig i læringsfasen, og gjerne også har PHP som sitt første språk. OOP kan være både enkelt og vanskelig, men det en tekst som skal opplyse om ideen i OOP må nødvendigvis ha en viss kompleksitet og inneholde en relativt stor mengde detaljer, og god kunnskap om emnet for å kunne overbringe det på en korrekt måte. Det å da blande sammen to relativt komplekse emner, og oppnå et halvgreit resultat, istedet for å gå for et av emnene og kanskje oppnå et godt resultat skurrer litt for meg.