Grunden
Grunderna
class
Grundläggande klassdefinitioner börjar med nyckelordet `class`, följt av ett klassnamn och därefter ett par klamrar `{}` som omsluter definitionerna av klassens egenskaper och metoder.
Klassnamnet kan vara vilken giltig etikett som helst, förutsatt att det inte är ett PHP-reserverat ord. Ett giltigt klassnamn börjar med en bokstav eller ett understreck, följt av ett valfritt antal bokstäver, siffror eller understreck. Som ett reguljärt uttryck skulle det uttryckas så här: `^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$`.
En klass kan innehålla sina egna konstanter, variabler (kallas "egenskaper") och funktioner (kallas "metoder").
Exempel #1 Enkel klassdefinition
<?php class SimpleClass { // Egenskapsdeklaration public $var = 'ett standardvärde'; // Metoddeklaration public function displayVar() { echo $this->var; } } ?>
Den pseudovariabeln `$this` är tillgänglig när en metod anropas inom ett objektkontext. `$this` är värdet på det anropande objektet.
Varning: Att anropa en icke-statisk metod statiskt utlöser ett fel. Före PHP 8.0.0 skulle detta generera ett deprecationsmeddelande och `$this` skulle vara odefinierad.
Exempel #2 Några exempel på pseudovariabeln $this
<?php class A { function foo() { if (isset($this)) { echo '$this är definierad ('; echo get_class($this); echo ")\n"; } else { echo "\$this är inte definierad.\n"; } } } class B { function bar() { A::foo(); } } $a = new A(); $a->foo(); A::foo(); $b = new B(); $b->bar(); B::bar(); ?>
Output av ovanstående exempel i PHP 7:
$this är definierad (A) Deprecated: Icke-statisk metod A::foo() bör inte anropas statiskt i %s på rad 27 $this är inte definierad. Deprecated: Icke-statisk metod A::foo() bör inte anropas statiskt i %s på rad 20 $this är inte definierad. Deprecated: Icke-statisk metod B::bar() bör inte anropas statiskt i %s på rad 32 Deprecated: Icke-statisk metod A::foo() bör inte anropas statiskt i %s på rad 20 $this är inte definierad.
Output av ovanstående exempel i PHP 8:
$this är definierad (A) Fatal error: Uncaught Error: Icke-statisk metod A::foo() kan inte anropas statiskt i %s :27 Stack trace: #0 {main} thrown in %s på rad 27
readonly klasser
Från och med PHP 8.2.0 kan en klass markeras med readonly-modifieraren. Att markera en klass som readonly lägger till readonly-modifieraren till varje deklarerad egenskap och förhindrar skapandet av dynamiska egenskaper. Dessutom är det omöjligt att lägga till stöd för dem genom att använda attributet `AllowDynamicProperties`. Ett försök att göra det utlöser ett kompileringstidfel.
<?php #[\AllowDynamicProperties] readonly class Foo { } // Fatalt fel: Kan inte tillämpa #[AllowDynamicProperties] på readonly-klass Foo ?>
Eftersom varken otypade eller statiska egenskaper kan markeras med readonly-modifieraren, kan readonly-klasser inte deklarera dem heller:
<?php readonly class Foo { public $bar; } // Fatalt fel: Readonly-egenskapen Foo::$bar måste ha typ ?> <?php readonly class Foo { public static int $bar; } // Fatalt fel: Readonly-klassen Foo kan inte deklarera statiska egenskaper ?>
En readonly-klass kan utökas om, och endast om, den underordnade klassen också är en readonly-klass.
new
För att skapa en instans av en klass måste nyckelordet `new` användas. Ett objekt kommer alltid att skapas om inte objektet har en konstruktor som definieras som kastar ett undantag vid fel. Klasser bör definieras före instansiering (och i vissa fall är detta ett krav).
Om en variabel som innehåller en sträng med namnet på en klass används med `new`, kommer en ny instans av den klassen att skapas. Om klassen finns i ett namnrymd, måste dess fullt kvalificerade namn användas vid detta.
Observera: Om det inte finns några argument att skicka till klassens konstruktor, kan parenteserna efter klassnamnet utelämnas.
Exempel #3 Skapa en instans
<?php $instance = new SimpleClass(); // Detta kan också göras med en variabel: $className = 'SimpleClass'; $instance = new $className(); // new SimpleClass() ?>
Från och med PHP 8.0.0 stöds användning av `new` med godtyckliga uttryck. Detta möjliggör mer komplex instansiering om uttrycket genererar en sträng. Uttrycken måste omslutas i parenteser.
Exempel #4 Skapa en instans med ett godtyckligt uttryck
<?php class ClassA extends \stdClass {} class ClassB extends \stdClass {} class ClassC extends ClassB {} class ClassD extends ClassA {} function getSomeClass(): string { return 'ClassA'; } var_dump(new (getSomeClass())); var_dump(new ('Class' . 'B')); var_dump(new ('Class' . 'C')); var_dump(new (ClassD::class)); ?>
Output av ovanstående exempel i PHP 8:
object(ClassA)#1 (0) { } object(ClassB)#1 (0) { } object(ClassC)#1 (0) { } object(ClassD)#1 (0) { }
I klasskontexten är det möjligt att skapa ett nytt objekt med `new self` och `new parent`.
När man tilldelar en redan skapad instans av en klass till en ny variabel, kommer den nya variabeln att få tillgång till samma instans som objektet som tilldelades. Detta beteende är detsamma när man skickar instanser till en funktion. En kopia av ett redan skapat objekt kan göras genom att klona det.
Exempel #5 Objektstilldelning
<?php $instance = new SimpleClass(); $assigned = $instance; $reference =& $instance; $instance->var = '$assigned kommer att ha detta värde'; $instance = null; // $instance och $reference blir null var_dump($instance); var_dump($reference); var_dump($assigned); ?>
Output av ovanstående exempel:
NULL NULL object(SimpleClass)#1 (1) { ["var"]=> string(30) "$assigned kommer att ha detta värde" }
Det är möjligt att skapa instanser av ett objekt på ett par sätt:
Exempel #6 Skapa nya objekt
<?php class Test { public static function getNew() { return new static(); } } class Child extends Test {} $obj1 = new Test(); // Med klassnamnet $obj2 = new $obj1(); // Genom variabeln som innehåller ett objekt var_dump($obj1 !== $obj2); $obj3 = Test::getNew(); // Med klassmetoden var_dump($obj3 instanceof Test); $obj4 = Child::getNew(); // Genom en underklassmetod var_dump($obj4 instanceof Child); ?>
Output av ovanstående exempel:
bool(true) bool(true) bool(true)
Det är möjligt att komma åt en medlem av ett nyligen skapat objekt i ett enda uttryck:
Exempel #7 Komma åt medlem av nyligen skapat objekt
<?php echo (new DateTime())->format('Y'); ?>
Output av ovanstående exempel:
2016
Observera: Före PHP 7.1 utvärderades inte argumenten om det inte fanns någon konstruktörsmetod definierad.
Egenskaper och metoder
Klassens egenskaper och metoder lever i separata "namnutrymmen", så det är möjligt att ha en egenskap och en metod med samma namn. Hänvisning till både en egenskap och en metod har samma notation, och om en egenskap kommer att nås eller en metod kommer att anropas beror enbart på sammanhanget, det vill säga om användningen är en variabelåtkomst eller ett funktionsanrop.
Exempel #8 Egenskapsåtkomst vs. metodanrop
<?php class Foo { public $bar = 'egenskap'; public function bar() { return 'metod'; } } $obj = new Foo(); echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL; ?>
Output av ovanstående exempel:
egenskap metod
Det betyder att det inte är direkt möjligt att anropa en anonym funktion som har tilldelats en egenskap. Istället måste egenskapen tilldelas en variabel först, till exempel. Det är möjligt att anropa en sådan egenskap direkt genom att omsluta den med parenteser.
Exempel #9 Anropa en anonym funktion lagrad i en egenskap
<?php class Foo { public $bar; public function __construct() { $this->bar = function() { return 42; }; } } $obj = new Foo(); echo ($obj->bar)(), PHP_EOL; ?>
Output av ovanstående exempel:
42
extends
En klass kan ärva konstanter, metoder och egenskaper från en annan klass genom att använda nyckelordet `extends` i klassdeklarationen. Det är inte möjligt att utöka flera klasser; en klass kan bara ärva från en bas-klass.
De ärvda konstanterna, metoderna och egenskaperna kan åsidosättas genom att återdeklarera dem med samma namn som definierats i basklassen. Men om basklassen har definierat en metod eller konstant som final, får de inte åsidosättas. Det är möjligt att komma åt de åsidosatta metoderna eller statiska egenskaperna genom att referera till dem med `parent::`.
Observera: Från och med PHP 8.1.0 kan konstanter deklareras som final.
Exempel #10 Enkel klassarv
<?php class ExtendClass extends SimpleClass { // Omdefiniera basklassens metod function displayVar() { echo "Utökad klass\n"; parent::displayVar(); } } $extended = new ExtendClass(); $extended->displayVar(); ?>
Output av ovanstående exempel:
Utökad klass ett standardvärde
Regler för signaturkompatibilitet
När man åsidosätter en metod måste dess signatur vara kompatibel med basklassens metod. Annars genereras ett fatalt fel, eller före PHP 8.0.0, ett fel på E_WARNING-nivå. En signatur är kompatibel om den respekterar variationsreglerna, gör en obligatorisk parameter valfri, lägger endast till valfria nya parametrar och inte begränsar utan endast slappnar av synligheten. Detta är känt som Liskov Substitution Principle, eller LSP för korthetens skull. Konstruktorn och privata metoder är undantagna från dessa regler för signaturkompatibilitet och kommer därför inte att utlösa ett fatalt fel vid en signaturmismatch.
Exempel #11 Kompatibla barnmetoder
<?php class Base { public function foo(int $a) { echo "Giltig\n"; } } class Extend1 extends Base { function foo(int $a = 5) { parent::foo($a); } } class Extend2 extends Base { function foo(int $a, $b = 5) { parent::foo($a); } } $extended1 = new Extend1(); $extended1->foo(); $extended2 = new Extend2(); $extended2->foo(1); ?>
Output av ovanstående exempel:
Giltig Giltig
Följande exempel visar att en barnmetod som tar bort en parameter eller gör en valfri parameter obligatorisk inte är kompatibel med basklassens metod.
Exempel #12 Fatalt fel när en barnmetod tar bort en parameter
<?php class Base { public function foo(int $a = 5) { echo "Giltig\n"; } } class Extend extends Base { function foo() { parent::foo(1); } } ?>
Output av ovanstående exempel i PHP 8:
Fatalt fel: Deklaration av Extend::foo() måste vara kompatibel med Base::foo(int $a = 5) i /in/evtlq på rad 13
Exempel #13 Fatalt fel när en barnmetod gör en valfri parameter obligatorisk
<?php class Base { public function foo(int $a = 5) { echo "Giltig\n"; } } class Extend extends Base { function foo(int $a) { parent::foo($a); } } ?>
Output av ovanstående exempel i PHP 8:
Fatalt fel: Deklaration av Extend::foo(int $a) måste vara kompatibel med Base::foo(int $a = 5) i /in/qJXVC på rad 13
Varning: Att byta namn på en metods parameter i en barnklass är inte en signaturkompatibilitet. Men detta avråds eftersom det kommer att resultera i ett runtime-fel om namngivna argument används.
Exempel #14 Fel vid användning av namngivna argument och parametrar har bytt namn i en barnklass
<?php class A { public function test($foo, $bar) {} } class B extends A { public function test($a, $b) {} } $obj = new B; // Skicka parametrar enligt A::test() kontrakt $obj->test(foo: "foo", bar: "bar"); // FEL! ?>
Output av ovanstående exempel:
Fatalt fel: Uncaught Error: Okänt namngivet argument $foo i /in/XaaeN:14 Stack trace: #0 {main} thrown in /in/XaaeN på rad 14
::class
Nyckelordet `class` används också för klassnamnsupplösning. För att erhålla det fullt kvalificerade namnet på en klass används `ClassName::class`. Detta är särskilt användbart med namnrymdsklasser.
Exempel #15 Klassnamnsupplösning
<?php namespace NS { class ClassName { } echo ClassName::class; } ?>
Output av ovanstående exempel:
NS\ClassName
Observera: Klassnamnsupplösning med `::class` är en kompileringstidsomvandling. Det betyder att när klassnamnsträngen skapas har ingen autoloading skett ännu. Som en konsekvens utökas klassnamn även om klassen inte existerar. Inget fel ges i det fallet.
Exempel #16 Saknad klassnamnsupplösning
<?php print Does\Not\Exist::class; ?>
Output av ovanstående exempel:
Does\Not\Exist
Från och med PHP 8.0.0 kan `::class` även användas på objekt. Denna upplösning sker vid runtime, inte vid kompileringstid. Dess effekt är densamma som att anropa `get_class()` på objektet.
Exempel #17 Objektupplösning
<?php namespace NS { class ClassName { } } $c = new ClassName(); print $c::class; ?>
Output av ovanstående exempel:
NS\ClassName
Nullsäkra metoder och egenskaper
Från och med PHP 8.0.0 kan egenskaper och metoder även nås med den "nullsäkra" operatorn `?->`. Den nullsäkra operatorn fungerar på samma sätt som egenskaps- eller metodåtkomst som ovan, förutom att om objektet som ska avrefereras är `null`, kommer `null` att returneras istället för att ett undantag kastas. Om avreferensen är en del av en kedja, hoppas resten av kedjan över.
Effekten är liknande att omsluta varje åtkomst med en `is_null()`-kontroll först, men mer kompakt.
Exempel #18 Nullsäkra operatorn
<?php // Från och med PHP 8.0.0, är denna rad: $result = $repository?->getUser(5)?->name; // Likvärdig med följande kodblock: if (is_null($repository)) { $result = null; } else { $user = $repository->getUser(5); if (is_null($user)) { $result = null; } else { $result = $user->name; } } ?>
Observera: Den nullsäkra operatorn används bäst när null anses vara ett giltigt och förväntat möjligt värde för en egenskap eller metods returvärde. För att indikera ett fel är det att föredra att kasta ett undantag.
Sidslut
Orginalhemsidan på Engelska :
PHP
Språkreferens
Språkreferens#Klasser_och_Objekt