Traits

Från Wiki.linux.se
Version från den 19 augusti 2024 kl. 05.02 av Admin (diskussion | bidrag)
(skillnad) ← Äldre version | Nuvarande version (skillnad) | Nyare version → (skillnad)
Hoppa till navigering Hoppa till sök

Traits

PHP implementerar ett sätt att återanvända kod som kallas Traits.

Traits är en mekanism för kodåteranvändning i enkelärvande språk som PHP. Ett Trait är avsett att minska vissa begränsningar av enkel arv genom att möjliggöra för en utvecklare att återanvända uppsättningar av metoder fritt i flera oberoende klasser som lever i olika klasshierarkier. Semantiken för kombinationen av Traits och klasser är definierad på ett sätt som minskar komplexiteten och undviker de typiska problemen som är förknippade med multipel arv och Mixins.

Ett Trait liknar en klass, men är endast avsett att gruppera funktionalitet på ett finfördelat och konsekvent sätt. Det är inte möjligt att instansiera ett Trait på egen hand. Det är ett komplement till traditionellt arv och möjliggör horisontell komposition av beteende; det vill säga tillämpningen av klassmedlemmar utan att kräva arv.

Exempel #1 Trait-exempel

<?php
trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}

class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}

class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
}
?>

Prioritet (Precedence) ¶

En ärvd medlem från en basklass överskrids av en medlem som infogats av ett Trait. Prioritetsordningen är att medlemmar från den aktuella klassen överskrider Trait-metoder, som i sin tur överskrider ärvda metoder.

Exempel #2 Prioritetsordning

<?php
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
?>

Det ovanstående exemplet kommer att skriva ut:

Hello World!

Exempel #3 Alternativ Prioritetsordning

<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class TheWorldIsNotEnough {
    use HelloWorld;
    public function sayHello() {
        echo 'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
$o->sayHello();
?>

Det ovanstående exemplet kommer att skriva ut:

Hello Universe!

Flera Traits ¶

Flera Traits kan infogas i en klass genom att lista dem i use-satsen, separerade med kommatecken.

Exempel #4 Användning av flera Traits

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World';
    }
}

class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo '!';
    }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

Det ovanstående exemplet kommer att skriva ut:

Hello World!

Konfliktlösning ¶

Om två Traits infogar en metod med samma namn genereras ett fatalt fel om konflikten inte uttryckligen löses.

För att lösa namngivningskonflikter mellan Traits som används i samma klass, måste insteadof-operatören användas för att välja exakt en av de motstridiga metoderna.

Eftersom detta endast tillåter att utesluta metoder kan as-operatören användas för att lägga till ett alias till en av metoderna. Observera att as-operatören inte byter namn på metoden och inte påverkar någon annan metod heller.

Exempel #5 Konfliktlösning

<?php
trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}
?>

Ändring av metodsynlighet

Med hjälp av as-syntaxen kan man också justera synligheten av metoden i den exponerande klassen.

Exempel #6 Ändring av metodsynlighet

<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

// Ändra synligheten för sayHello
class MyClass1 {
    use HelloWorld { sayHello as protected; }
}

// Alias för metoden med ändrad synlighet
// sayHello synlighet inte ändrad
class MyClass2 {
    use HelloWorld { sayHello as private myPrivateHello; }
}
?>

Traits sammansatta av Traits

Precis som klasser kan använda traits kan även andra traits göra det. Genom att använda ett eller flera traits i en trait-definition kan den delvis eller helt bestå av medlemmar definierade i dessa andra traits.

Exempel #7 Traits sammansatta av Traits

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>

Det ovanstående exemplet kommer att skriva ut:

Hello World!

Abstrakta Trait-medlemmar ¶

Traits stöder användningen av abstrakta metoder för att ställa krav på den exponerande klassen. Offentliga, skyddade och privata metoder stöds. Före PHP 8.0.0 stöddes endast offentliga och skyddade abstrakta metoder.

Varning: Från och med PHP 8.0.0 måste signaturen för en konkret metod följa reglerna för signaturkompatibilitet. Tidigare kunde dess signatur vara annorlunda.

Exempel #8 Uttrycka krav med abstrakta metoder

<?php
trait Hello {
    public function sayHelloWorld() {
        echo 'Hello'.$this->getWorld();
    }
    abstract public function getWorld();
}

class MyHelloWorld {
    private $world;
    use Hello;
    public function getWorld() {
        return $this->world;
    }
    public function setWorld($val) {
        $this->world = $val;
    }
}
?>

Statiska Trait-medlemmar ¶

Traits kan definiera statiska variabler, statiska metoder och statiska egenskaper.

Notera: Från och med PHP 8.1.0 är det föråldrat att anropa en statisk metod, eller komma åt en statisk egenskap direkt på ett trait. Statiska metoder och egenskaper ska endast användas på en klass som använder traitet.

Exempel #9 Statiska variabler

<?php
trait Counter {
    public function inc() {
        static $c = 0;
        $c = $c + 1;
        echo "$c\n";
    }
}

class C1 {
    use Counter;
}

class C2 {
    use Counter;
}

$o = new C1(); $o->inc(); // skriver ut 1
$p = new C2(); $p->inc(); // skriver ut 1
?>

Exempel #10 Statiska metoder

<?php
trait StaticExample {
    public static function doSomething() {
        return 'Doing something';
    }
}

class Example {
    use StaticExample;
}

Example::doSomething();
?>

Exempel #11 Statiska egenskaper

<?php
trait StaticExample {
    public static $static = 'foo';
}

class Example {
    use StaticExample;
}

echo Example::$static;
?>

Egenskaper ¶

Traits kan också definiera egenskaper.

Exempel #12 Definiera egenskaper

<?php
trait PropertiesTrait {
    public $x = 1;
}

class PropertiesExample {
    use PropertiesTrait;
}

$example = new PropertiesExample;
$example->x;
?>

Om ett trait definierar en egenskap kan en klass inte definiera en egenskap med samma namn om den inte är kompatibel (samma synlighet och typ, readonly-modifierare och initialvärde), annars genereras ett fatalt fel.

Exempel #13 Konfliktlösning

<?php
trait PropertiesTrait {
    public $same = true;
    public $different1 = false;
    public bool $different2;
    public bool $different3;
}

class PropertiesExample {
    use PropertiesTrait;
    public $same = true;
    public $different1 = true; // Fatalt fel
    public string $different2; // Fatalt fel
    readonly protected bool $different3; // Fatalt fel
}
?>

Konstanter ¶

Traits kan, från och med PHP 8.2.0, också definiera konstanter.

Exempel #14 Definiera konstanter

<?php
trait ConstantsTrait {
    public const FLAG_MUTABLE = 1;
    final public const FLAG_IMMUTABLE = 5;
}

class ConstantsExample {
    use ConstantsTrait;
}

$example = new ConstantsExample;
echo $example::FLAG_MUTABLE; // 1
?>

Om ett trait definierar en konstant kan en klass inte definiera en konstant med samma namn om den inte är kompatibel (samma synlighet, initialvärde och finalitet), annars genereras ett fatalt fel.

Exempel #15 Konfliktlösning

<?php
trait ConstantsTrait {
    public const FLAG_MUTABLE = 1;
    final public const FLAG_IMMUTABLE = 5;
}

class ConstantsExample {
    use ConstantsTrait;
    public const FLAG_IMMUTABLE = 5; // Fatalt fel
}
?>


Sidslut

Orginalhemsidan på Engelska : https://www.php.net/manual/en/language.oop5.traits.php
PHP
Språkreferens
Språkreferens#Klasser_och_Objekt