View Single Post
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