32
Tags:
php
Skrevet af
Bruger #714
@ 17.03.2004
PHP5 er ved at blive udviklet, faktisk er der allerede kommet 4 beta udgaver. Men hvad er det der gør denne version helt specielt? Efter min mening er det klart at de har valgt at skifte til Zend Engine 2. Zend Enginen er det der styrer mange af tingene i PHP, men hvad er der så sket fra version 1 til version 2? Det er præcis det jeg vil beskrive i denne artikel.
Bemærk venligst, denne artikel vil beskrive de punkter der står om på:
http://www.php.net/zend-engine-2.php så hvis i synes det ligner en klon, er det nok derfor
.
De 2 hovedpunkter vi skal se på er
1. OOP
2. Exception handling
OOP
PHP5 tilføjer en masse nye ting og muligheder for at skrive Objekt Orienteret Programmering. Dem af jer der før har programmeret f.eks. c++, C#, VB(.NET), osv, kender allerede en masse af de svagheder som den gamle objekt model havde. Bare for at nævne et par ting, så var der ingen mulighed for at deklare variabler/metoder for public, protected eller private, man kunne ikke lave abstracte klasser eller interfaces og et par ting til.
Men lad os starte ligepå og hårdt
De 3 gyldne p'er
De 3 gyldne p'er er:
Public
Protected
Private
De styrer hvilken "adgang" man har til forskellige variabler/metoder i en klasse. Det engelske ord "public" betyder offentlig og det er det samme i det her tilfælde, deklærer du en variabel eller metode for public så har alle adgang til variablen/metoden. Protected betyder beskyttet og her gælder det at kun klasser der udvider fra klassen hvor variablen/metoden bliver deklaret for protected, private variabler/metoder kan kun tilgåes via klassen hvor de bliver deklaret for private.
Man deklarer noget public/protected/private ved at skrive det foran det man vil deklare, f.eks.
public $foo;
protected $bar;
private function minFunktion(){}
Hvad kan det så bruges til? Jo når man programmerer OO så er det dårlig skik at lade folk tilgå en variabel direkte $klasse->variabel = "haha", f.eks. for hvad nu hvis "$klasse->variabel" faktisk skulle være et array? Derfor gør man normalt det at man laver metoder til at sætte og få indholdet fra variabler, dvs. sådan her:
class Klasse {
private $variabel = array();
function Klasse($variabel){
$this->setVariabel($variabel);
}
function getVariabel(){
return $this->variabel;
}
function setVariabel($value){
if(is_array($value)){
$this->variabel = $value;
}
}
}
Bemærk at jeg ikke sætter pulibc/protected/private foran nogen af mine metoder, i dette tilfælde betyder det ikke noget da de så bliver deklaret public (i de fleste programmerings sprog ville det dog være private, men i php er det public for at man ikke skal have alt for mange til at rette deres scripts da det jo ellers altid har været public). Det er dog en god ide at skrive public foran, så man selv har styr på det, men nu skrev jeg det ikke for at vise et eksempel uden.
Mht. eksemplet, så ville man jo normalt også skrive en fejlmeddelelse hvis $value ikke var et array, men fejlhåndtering kommer jeg til længere nede, så det venter vi med
.
Konstruktører og destruktører
Konstruktører i PHP er ingen nyhed, men destruktører er. I tideligere versioner af PHP har man skulle lave en funktion med klassens navn for at den blev til en konstruktør, men i PHP5 skal man kalde den __construct, dette er faktisk ret smart da PHP ikke kalder en "base klassens" konstruktør af sig selv (dvs. hvis du laver klassen Base og så laver en klasse der hedder Extension så vil Base klassen konstruktør ikke blive kaldt når du opretter et nyt Extension objekt). Men den kan du selv kalde ved at tilføje parent::__construct(); Men hvis Base klassens konstruktør hedder Base, så skal man ændre linjen parent:
ase() hvis man ændrer navnet Base til noget andet. Dog vil PHP5 lede efter en metode der hedder klassens navn hvis den ikke kan finde en __construct metode.
Destruktører i PHP5 hedder (ja du har sikkert allerede gættet det) __destruct, og kaldes når et objekt bliver destrueret. Meget smart hvis man f.eks. har lavet en klasse til styring af en database så kan man lukke forbindelsen i sin __destruct metode.
Abstrakte klasser
PHP5 indfører også abstrakte klasser. Abstrakte klasser er klasser der ikke kan laves instanser af (det her vil være umuligt: $obj = new AbstraktKlasse
. En abstrakt klasse kan godt definere metoder som er implementeret (skrevet), den kan også indeholde variabler. Den kan dog også indeholde abstrakte funktioner (funktioner som ikke er skrevet), hvis man laver en klasse der stammer fra en abstrakt klasse den indeholde de funktioner som er abstrakte i den klasse den arver fra. Et eksempel på en abstrakt klasse kan være:
abstract class Shape {
abstract public function getArea();
}
class Rectangle extends Shape {
private $height, $width;
public function __construct($height, $width){
$this->height = (int) $height;
$this->width = (int) $width;
}
public function getArea(){
return $this->height * $this->width;
}
}
class Square extends Shape {
private $sideLength;
public function __construct($sideLength){
$this->sideLength = (int) $sideLength;
}
public function getArea(){
return $this->sideLength * $this->sideLength;
}
}
class Triangle extends Shape {
private $height, $width;
public function __construct($height, $width){
$this->height = (int) $height;
$this->width = (int) $width;
}
public function getArea(){
return 0.5 * $this->height * $this->width;
}
}
Dog er her ikke givet noget eksempel på at den abstrakte klasse også kan indeholde variabler og metoder der er skrevet, men det bør vel ikke være nødvendigt?
Interfaces
Interfaces er lidt hen af det samme som en abstrakt klasse, forskellen fra den abstrakte klasse er at et interface kun kan indeholde de "abstrakte" metoder (som dog ikke er abstrakte her, men princippet er det samme), et eksempel på et interface kunne være:
interface ICheckable {
public function check($value);
}
I nogle kodesprog begynder interfaces normalt med et stort I, i andre ikke, det er op til dig selv hvad du vil kalde dine interfaces. Nor man så skal bruge et interface deklarer man sin klasse således:
class CheckBox implements ICheckable {
private $check;
public function check($value){
$this->check = (bool) $value;
}
}
Det smarte ved interfaces er at hvis man ved at en klasse indeholder et interface ved man at det har de metoder som der er i interfaced. Men hvordan kan man så tjekke om en klasse indeholder interfaced? PHP5 introducerer også nøjleordet "instanceof", som bruges sådan her:
if($klasse instanceof Klasse)....
Instanceof virker også på interfaces, dvs. i vores tilfælde kan vi chekke med:
$checkbox = new Checkbox;
if($checkbox instanceof ICheckable)...
Class type hint
(Undskyld for det engelske, men kunne ikke lige finde den danske oversættelse)
Det er lidt svært at forklare uden et eksempel, så lad os starte med et eksempel:
class Foo {
}
class Bar extends Foo {
}
class Baz {
}
function useFoo(Foo $foo){
//Gør noget med $foo
}
$foo = new Foo;
useFoo($foo);
$bar = new Bar;
useFoo($bar);
$baz = new Baz;
//useFoo($baz); Vil ikke virke! Da baz ikke relaterer til foo på nogen måde
Kort sagt kan man bestemme hvilken klasse en paramenter skal være af. Men klasser der stammer fra den valgte klasse vil også blive godkendt.
Final; nej vi er ikke færdige
Med nøjleordet final kan du gøre så en metode ikke kan overskrives. F.eks.
class Klasse {
final public function unChangeable(){}
}
class Klasse2 extends Klasse {
// public function unChangeable(){}
}
Metoden unChangeable kan ikke overskrives af klasse2, derfor er linjen udkommenteret.
Man kan også gøre en klasse "final" (f.eks final class KanIkkeAEndres).
Kloning af objekter
I tideligere versioner af PHP ville man altid overføre et objekt via værdi når man f.eks. udførte denne kode:
class MinKlasse {
protected $var;
public function __construct($var){
$this->var = $var;
}
public function getVar(){
return $this->var;
}
public function setVar($var){
$this->var = $var;
}
}
$obj1 = new MinKlasse(12);
$obj2 = $obj1;
$obj2->setVar(5);
echo $obj1->getVar();
I PHP4 ville det skrive "12" ud, men i PHP5 vil der blive skrevet 5 ud, da $obj2 = $obj1 linjen i PHP5 vil svare til følgende linie i PHP4:
$obj2 = &$obj1;
Objekter i PHP5 bliver nemlig overført via reference. Men hvad nu hvis man gerne vil klone et objekt, altså tildele efter værdi og ikke reference? Dertil bruges den nye funktion __clone() ($obj2 = $obj1->__clone()).
NOTE: Sådan står det beskrevet på siden jeg gav et link til i starten af artiklen, men da jeg prøvede med BETA4 så meldte den en fejl om at jeg skulle bruge clone $obj2, og dette gav samme mening, så hvis det fejler med $obj2 = $obj1->__clone() så prøv $obj2 = clone $obj1)
Det er så så smart lavet at man rent faktisk kan lave en funktion der hedder __clone som bliver kørt når man kloner et objekt
, et lille eksempel (fra php.net):
class MyCloneable {
static $id = 0;
function MyCloneable() {
$this->id = self::$id++;
}
function __clone() {
$this->name = $that->name;
$this->address = "New York";
$this->id = self::$id++;
}
}
$obj = new MyCloneable();
$obj->name = "Hello";
$obj->address = "Tel-Aviv";
print $obj->id . "\\n";
$obj = $obj->__clone();
print $obj->id . "\\n";
print $obj->name . "\\n";
print $obj->address . "\\n";
Konstanter
En klasse kan nu også indeholde konstanter, en konstant er det "modsatte" af en variabel, da dens indhold er konstant (den ændrer sig ikke), hvormod en variabels indhold er variabel (den ændrer sig), man definerer en konstant således:
class Klasse {
const minKonstant = "hej hej";
}
Konstanten kan så bruges via Klasse::minKonstant.
3 nye metoder; __call, __get og __set
Disse metoder kan bruges til at "fake" metoder og variabler. F.eks.
class Klasse {
public function __call($funcName, $args;){
echo "Du kaldte på funktionen {$funcName}";
//Her kan du så bruge $funcName, som indeholdet navnet på funktionen der blev kaldt
//Og $args, der indeholder argumenterne i samme format som man bruger func_get_args (http://php.net/func_get_args)
return "Du kaldte på mig ($funcName)";
}
public function __get($varName){
//Her bruges $varName, til at finde ud af hvilken "variabel" der blev spurgt efter, og så kan du så retunere den.
if(isset($this->$varName)){
return $this->$varName;
} else {
return "Variablen findes ikke";
}
}
public function __set($varName, $value){
//Samme princip som __get, men her forsøger brugeren bare at give en værdi til en variabel
$this->$varName = $value;
}
}
$obj = new Klasse;
$obj->HahaSejt("Mine argumenter", "Nummer 2");
$obj->minVariabel = "Haha";
echo $obj->minVariabel;
Du kan forhåbentlig selv se princippet i det, meget smart
.
En sidste metode __toString
Kort og godt så går denne metode ud på at du kan type-caste dit objekt til en string når du har angivet en __toString metode som retunerer en string.
class MinKlasse {
public function __toString(){
return "MinKlasse er en god klasse";
}
}
$obj = new MinKlasse;
$str = (string) $obj;
echo $str;
echo $obj;
Dette vil udskrive "MinKlasse er en god klasse" 2 gange.
Exception handling
Så kom vi til det, den anden store ændring i PHP5. PHP har nu fået indbygget et "fejl håndteringssystem". Det bruges ligesom i f.eks. c++ og java, med try og catch statements. Hvis man har en kode hvor man tror at der kan forekomme en fejl så starter man en try block (try { kode... }). Hvis der inde i den try blok bliver "kastet" en exception træder det hele i kræft. Man kan kaste en exception via throw
Exception klasse. Exception klasse kan enten være et ny oprettet objekt (new Exception f.eks.), eller en variabel der indeholder en exception klasse ($exception f.eks.). Disse exceptions som der bliver kastet med (
) "griber" man så i en catch blok og så håndterer man fejlen (f.eks. skriver den ud og stopper scriptet). Et lille eksempel:
try {
throw new Exception("En exception blev kastet");
echo "Hej hej";
} catch(Exception $e){
echo $e->getMessage();
}
I dette eksempel vil selve scriptet bare outputte "En exception blev kastet", da scriptet aldrig når ned til "echo "Hej hej" (PHP hopper ud af try blokken og direkte ned til catch blokken). Hvis du gerne vil have PHP til at gøre noget ligeuanset om der blev kastet en exception eller ej, så kan du tilføje en finally blok til sidst
try {
throw new Exception("En exception blev kastet");
echo "Hej hej";
} catch(Exception $e){
echo $e->getMessage();
} finally {
echo "Endelig";
}
Der står noget mere om fejlhåndtering på
http://www.php.net/zend-engine-2.php som er værd at læse.
Det var det
Ja, det var det, dog er der et par ting jeg ikke har nævnt som står nærmere beskrevet på
http://www.php.net/zend-engine-2.php Så det må du selv læse
. Men de basale ændringer burde være på plads.
Håber du har fået noget ud af artiklen og begynder at glæde dig til PHP5 (jeg glæder mig da, og er allerede ved at skrive en hjemmeside der benytter de nye fordele ved PHP5).
Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.
Del også gerne artiklen med dine Facebook venner:
Kommentarer (10)
Rigtig god artikel Kaare (selvom det ligner lidt en klon, som du selv nævner). Jeg glæder mig også meget til PHP5, da jeg har baggrund i mere objektorienterede sprog....dejligt at PHP endelig tager det næste skridt i den retning!
Jeg er begyndt at indsætte kommentarer i alle mine klasser om hvad der er ment som public, protected og private, så jeg hurtigt kan udnytte den nye styring af klasserne, når PHP5 kommer ud :-)
Tak for kommentaren. Men ja, det var egentlig også ment som en "klon" da jeg ikke har kunne finde nogen danske forklaringer på PHP5, og da det slet ikke er nævnt herinde på udvikleren, lyder det jo som om at det er/var et dødt emne, og da det nu er så gode nye ting PHP5 kommer med, ville jeg ikke have det at fortsatte sådan. Men alt det med kommentarer osv. i mine klasser, det gad jeg nu ikke, jeg installerede bare PHP5 da min side nok først bliver færdig når PHP5 udkommer. Men det er rigtig fedt at arbejde med, glæd jer til det!
Synes det er godt at du nævner at det er en klo og jeg tror at det på mange måder hjælper at man laver en dansk version af artiklerne da der er mange som ikke er gode til engelsk og hellere fortrækker at læse dansk!
Jeg vil i øvrigt lige nævne at fra og med PHP5-RC1 så har de ændret måden hvorpå __toString() fungerer (jeg er ikke vild med den ændring).
Det er nu ikke muligt at få kaldt __toString ved at typekaste objektet til string. Nu vil __toString kun blive kaldt når man udskriver objektet (echo eller print). Men man kan jo altid kalde __toString selv...
Tilføjer lige en kommentar mere:
Der er ingen mulighed for at bruge final i try..catch.
Udover det ville jeg meget gerne høre nogle flere kommentarer. Evt. om i kunne lide flere artikler om PHP5 fra min side.
Ser sgu meget godt ud selvom jeg ikke forstår så meget af det... men man lærer da lidt
Fatter godt at du gør som du gør, men fatter ikke helt præcist hvorfor du gør som du gør... hvis du forstår hvad jeg mener
Haiii...
Jeg (vil gerne) igang med 1 3d chat.. Hjælpe mig??
DD
KnuZz
Zandra - få dit et liv, du er hjernelam.
ellers meget god artikel.
OK artikel, men du forklarer ikke alting grundigt nok synes jeg. Class type hint kunne ikke forklares dårligere
2,5, men kan man ik så du får 3
Okaay du forvirre mig TOTALT!
Du skal være
logget ind for at skrive en kommentar.