Heim  >  Artikel  >  Backend-Entwicklung  >  So implementieren Sie neue Merkmale der Code-Wiederverwendung in PHP

So implementieren Sie neue Merkmale der Code-Wiederverwendung in PHP

coldplay.xixi
coldplay.xixinach vorne
2020-07-27 17:01:331711Durchsuche

So implementieren Sie neue Merkmale der Code-Wiederverwendung in PHP

Ich bin beim Lesen des yii2-Quellcodes mit Merkmalen in Kontakt gekommen, also habe ich ihn studiert und einen Blog geschrieben, um ihn aufzuzeichnen.

Seit PHP 5.4.0 implementiert PHP eine Methode zur Code-Wiederverwendung namens Traits.

Traits ist ein Code-Wiederverwendungsmechanismus für Sprachen mit einfacher Vererbung wie PHP. Merkmale sollen die Einschränkungen von Sprachen mit einfacher Vererbung verringern und Entwicklern die freie Wiederverwendung von Methodensätzen in unabhängigen Klassen innerhalb verschiedener Hierarchien ermöglichen. Die Semantik von Merkmalen und die Klassenzusammensetzung definieren eine Möglichkeit, die Komplexität zu reduzieren und die typischen Probleme zu vermeiden, die mit traditioneller Mehrfachvererbung und Mixins verbunden sind.

Trait ähnelt einer Klasse, soll aber lediglich Funktionalität auf feinkörnige und konsistente Weise kombinieren. Ein Merkmal kann nicht allein instanziiert werden. Es fügt der herkömmlichen Vererbung eine Kombination horizontaler Funktionen hinzu, d. h. Mitglieder von Anwendungsklassen müssen nicht vererbt werden.

Merkmalsbeispiel

Der Code lautet wie folgt:

<?php
trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
}
?>

Priorität

Von der Basisklasse geerbte Mitglieder sind eingefügt durch Merkmal, das von Mitgliedern abgedeckt wird. Die Rangfolge besteht darin, dass Mitglieder der aktuellen Klasse die Methoden des Merkmals überschreiben und das Merkmal die geerbten Methoden überschreibt.

Beispiel für eine Prioritätsreihenfolge

Der Code lautet wie folgt:

<?php
class Base {
    public function sayHello() {
        echo &#39;Hello &#39;;
    }
}
trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo &#39;World!&#39;;
    }
}
class MyHelloWorld extends Base {
    use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
?>

Die obige Routine gibt Folgendes aus: Hallo Welt!

SayWorld, wo Mitglieder von der Basis geerbt haben Klasse werden eingefügt. Abgedeckt durch die sayHello-Methode in Trait. Sein Verhalten stimmt mit den in der MyHelloWorld-Klasse definierten Methoden überein. Die Rangfolge ist, dass Methoden in der aktuellen Klasse Merkmalsmethoden überschreiben, die wiederum Methoden in der Basisklasse überschreiben.

Ein weiteres Beispiel für eine Prioritätsreihenfolge

Der Code lautet wie folgt:

<?php
trait HelloWorld {
    public function sayHello() {
        echo &#39;Hello World!&#39;;
    }
}
class TheWorldIsNotEnough {
    use HelloWorld;
    public function sayHello() {
        echo &#39;Hello Universe!&#39;;
    }
}
$o = new TheWorldIsNotEnough();
$o->sayHello();
?>

Die obige Routine gibt Folgendes aus: Hallo Universum!

Mehrere Merkmale

werden durch Kommas getrennt. Mehrere Merkmale werden in der Verwendungsanweisung aufgeführt und können alle in eine Klasse eingefügt werden.

Beispiele für die Verwendung mehrerer Merkmale

Der Code lautet wie folgt:

<?php
trait Hello {
    public function sayHello() {
        echo &#39;Hello &#39;;
    }
}
trait World {
    public function sayWorld() {
        echo &#39;World&#39;;
    }
}
class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo &#39;!&#39;;
    }
}
$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

Die obige Routine gibt Folgendes aus: Hallo Welt!

Konflikt Auflösung

Wenn zwei Merkmale eine Methode mit demselben Namen einfügen, wird ein schwerwiegender Fehler generiert, wenn der Konflikt nicht explizit gelöst wird.

Um den Namenskonflikt mehrerer Merkmale in derselben Klasse zu lösen, müssen Sie den Statt-Operator verwenden, um explizit anzugeben, welche der widersprüchlichen Methoden verwendet werden sollen.

Mit der obigen Methode können nur andere Methoden ausgeschlossen werden. Der as-Operator kann eine der widersprüchlichen Methoden unter einem anderen Namen einführen.

Ein Beispiel für Konfliktlösung

Der Code lautet wie folgt:

<?php
trait A {
    public function smallTalk() {
        echo &#39;a&#39;;
    }
    public function bigTalk() {
        echo &#39;A&#39;;
    }
}
trait B {
    public function smallTalk() {
        echo &#39;b&#39;;
    }
    public function bigTalk() {
        echo &#39;B&#39;;
    }
}
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;
    }
}
?>

In diesem Fall verwendet Talker die Merkmale A und B. Da A und B widersprüchliche Methoden haben, definieren sie die Verwendung von smallTalk aus Merkmal B und bigTalk aus Merkmal A.

Aliased_Talker verwendet den as-Operator, um talk als Alias ​​von Bs bigTalk zu definieren.

Ändern Sie die Zugriffskontrolle der Methode

Die Verwendung der as-Syntax kann auch zum Anpassen der Zugriffskontrolle der Methode verwendet werden.

Ein Beispiel für die Änderung der Zugriffskontrolle einer Methode

Der Code lautet wie folgt:

<?php
trait HelloWorld {
    public function sayHello() {
        echo &#39;Hello World!&#39;;
    }
}
// 修改 sayHello 的访问控制
class MyClass1 {
    use HelloWorld { sayHello as protected; }
}
// 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化
class MyClass2 {
    use HelloWorld { sayHello as private myPrivateHello; }
}
?>

Trait aus Trait zusammensetzen

So wie Klassen Merkmale verwenden können, können auch andere Merkmale Merkmale verwenden. Durch die Verwendung eines oder mehrerer Merkmale bei der Definition eines Merkmals können einige oder alle Mitglieder anderer Merkmale kombiniert werden.

Ein Beispiel für das Zusammensetzen von Merkmalen aus Merkmalen

Der Code lautet wie folgt:

<?php
trait Hello {
    public function sayHello() {
        echo &#39;Hello &#39;;
    }
}
trait World {
    public function sayWorld() {
        echo &#39;World!&#39;;
    }
}
trait HelloWorld {
    use Hello, World;
}
class MyHelloWorld {
    use HelloWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>

Die obige Routine gibt Folgendes aus: Hallo Welt!

Abstraktion von Trait-Mitgliedern

Um Anforderungen an die verwendeten Klassen durchzusetzen, unterstützen Traits die Verwendung abstrakter Methoden.

Zeigt ein Beispiel für die Durchsetzung von Anforderungen durch abstrakte Methoden an

Der Code lautet wie folgt:

<?php
trait Hello {
    public function sayHelloWorld() {
        echo &#39;Hello&#39;.$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;
    }
}
?>

Statisches Mitglied von Trait

Merkmale können durch statische Mitglieder und statische Methoden definiert werden.

Ein Beispiel für eine statische Variable

Der Code lautet wie folgt:

<?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(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>

Ein Beispiel für eine statische Methode

Der Code lautet wie folgt folgt:

<?php
trait StaticExample {
    public static function doSomething() {
        return &#39;Doing something&#39;;
    }
}
class Example {
    use StaticExample;
}
Example::doSomething();
?>

Beispiele für statische Variablen und statische Methoden

Der Code lautet wie folgt:

<?php
trait Counter {
    public static $c = 0;
    public static function inc() {
        self::$c = self::$c + 1;
        echo self::$c . "\n";
    }
}
class C1 {
    use Counter;
}
class C2 {
    use Counter;
}
C1::inc(); // echo 1
C2::inc(); // echo 1
?>

Attribute
Trait kann auch Attribute definieren .

Beispiel für die Definition von Attributen

Der Code lautet wie folgt:

<?php
trait PropertiesTrait {
    public $x = 1;
}
class PropertiesExample {
    use PropertiesTrait;
}
$example = new PropertiesExample;
$example->x;
?>

Wenn ein Merkmal ein Attribut definiert, kann die Klasse kein Attribut mit definieren derselbe Name, sonst ein Fehler. Wenn die Definition der Eigenschaft in der Klasse mit ihrer Definition im Merkmal kompatibel ist (gleiche Sichtbarkeit und gleicher Anfangswert), dann ist die Fehlerstufe E_STRICT, andernfalls handelt es sich um einen schwerwiegenden Fehler.

Beispiele für Konflikte

Der Code lautet wie folgt:

<?php
trait PropertiesTrait {
    public $same = true;
    public $different = false;
}
class PropertiesExample {
    use PropertiesTrait;
    public $same = true; // Strict Standards
    public $different = true; // 致命错误
}
?>

Unterschiede in der Verwendung

Beispiele verschiedener Verwendungszwecke

Der Code lautet wie folgt:

<?php
namespace Foo\Bar;
use Foo\Test;  // means \Foo\Test - the initial \ is optional
?>
<?php
namespace Foo\Bar;
class SomeClass {
    use Foo\Test;   // means \Foo\Bar\Foo\Test
}
?>

Die erste Verwendung ist die Verwendung von FooTest für den Namespace, was gefunden wird, ist FooTest, die zweite Verwendung ist die Verwendung eines Merkmals, was gefunden wird istFooBarFooTest.

__CLASS__ und __TRAIT__
__CLASS__ geben den Klassennamen des verwendeten Merkmals zurück, __TRAIT__ gibt den Merkmalsnamen zurück

Das Beispiel ist wie folgt

Der Code lautet wie folgt:

<?php
trait TestTrait {
    public function testMethod() {
        echo "Class: " . __CLASS__ . PHP_EOL;
        echo "Trait: " . __TRAIT__ . PHP_EOL;
    }
}
class BaseClass {
    use TestTrait;
}
class TestClass extends BaseClass {
}
$t = new TestClass();
$t->testMethod();
//Class: BaseClass
//Trait: TestTrait

Trait Singleton

Das Beispiel lautet wie folgt

Der Code lautet wie folgt:

<?php
trait singleton {    
    /**
     * private construct, generally defined by using class
     */
    //private function __construct() {}
    public static function getInstance() {
        static $_instance = NULL;
        $class = __CLASS__;
        return $_instance ?: $_instance = new $class;
    }
    public function __clone() {
        trigger_error(&#39;Cloning &#39;.__CLASS__.&#39; is not allowed.&#39;,E_USER_ERROR);
    }
    public function __wakeup() {
        trigger_error(&#39;Unserializing &#39;.__CLASS__.&#39; is not allowed.&#39;,E_USER_ERROR);
    }
}
/**
* Example Usage
*/
class foo {
    use singleton;
    private function __construct() {
        $this->name = &#39;foo&#39;;
    }
}
class bar {
    use singleton;
    private function __construct() {
        $this->name = &#39;bar&#39;;
    }
}
$foo = foo::getInstance();
echo $foo->name;
$bar = bar::getInstance();
echo $bar->name;

Trait-Methoden aufrufen

Obwohl es nicht offensichtlich ist, kann es sein, dass die Trait-Methode als statische Methode in einer normalen Klasse definiert werden kann genannt

实例如下

代码如下:

<?php 
trait Foo { 
    function bar() { 
        return &#39;baz&#39;; 
    } 
} 
echo Foo::bar(),"\\n"; 
?>

相关学习推荐:PHP编程从入门到精通

Das obige ist der detaillierte Inhalt vonSo implementieren Sie neue Merkmale der Code-Wiederverwendung in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:jb51.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen