Maison  >  Article  >  développement back-end  >  Comment implémenter de nouvelles fonctionnalités de réutilisation de code en PHP

Comment implémenter de nouvelles fonctionnalités de réutilisation de code en PHP

coldplay.xixi
coldplay.xixiavant
2020-07-27 17:01:331792parcourir

Comment implémenter de nouvelles fonctionnalités de réutilisation de code en PHP

Je suis entré en contact avec des traits en lisant le code source de yii2, je l'ai donc étudié et écrit un blog pour l'enregistrer.

Depuis PHP 5.4.0, PHP implémente une méthode de réutilisation de code appelée traits.

Traits est un mécanisme de réutilisation de code pour les langages à héritage unique comme PHP. Les traits sont conçus pour réduire les contraintes des langages à héritage unique et permettre aux développeurs de réutiliser librement des ensembles de méthodes dans des classes indépendantes au sein de différentes hiérarchies. La sémantique des traits et la composition des classes définissent un moyen de réduire la complexité et d'éviter les problèmes typiques associés à l'héritage multiple et aux mixins traditionnels.

Le trait est similaire à une classe, mais est uniquement destiné à combiner des fonctionnalités de manière fine et cohérente. Le trait ne peut pas être instancié par lui-même. Il ajoute une combinaison de fonctionnalités horizontales à l'héritage traditionnel ; c'est-à-dire que les membres des classes d'application n'ont pas besoin d'être hérités.

Exemple de trait

Le code est le suivant :

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

Priorité

Les membres hérités de la classe de base sont inséré par trait couvert par les membres. L'ordre de priorité est que les membres de la classe actuelle remplacent les méthodes du trait et que le trait remplace les méthodes héritées.

Exemple d'ordre de priorité

Le code est le suivant :

<?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();
?>

La routine ci-dessus affichera : Hello World !

SayWorld où les membres ont hérité de la base les classes sont insérées Couvert par la méthode sayHello dans Trait. Son comportement est cohérent avec les méthodes définies dans la classe MyHelloWorld. L'ordre de priorité est que les méthodes de la classe actuelle remplacent les méthodes de trait, qui à leur tour remplacent les méthodes de la classe de base.

Un autre exemple d'ordre de priorité

Le code est le suivant :

<?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();
?>

La routine ci-dessus affichera : Bonjour Univers !

Plusieurs traits

sont séparés par des virgules. Plusieurs traits sont répertoriés dans la déclaration d'utilisation, et ils peuvent tous être insérés dans une classe.

Exemples d'utilisation de plusieurs traits

Le code est le suivant :

<?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();
?>

La routine ci-dessus affichera : Hello World !

Conflit résolution

Si deux traits insèrent une méthode du même nom, une erreur fatale sera générée si le conflit n'est pas résolu explicitement.

Afin de résoudre le conflit de nom de plusieurs traits dans la même classe, vous devez utiliser l'opérateur placeof pour spécifier explicitement laquelle des méthodes en conflit utiliser.

La méthode ci-dessus permet uniquement d'exclure d'autres méthodes. L'opérateur as peut introduire l'une des méthodes en conflit sous un autre nom.

Un exemple de résolution de conflit

Le code est le suivant :

<?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;
    }
}
?>

Dans ce cas, Talker utilise les traits A et B. Puisque A et B ont des méthodes contradictoires, ils définissent l'utilisation de smallTalk à partir du trait B et bigTalk à partir du trait A.

Aliased_Talker utilise l'opérateur as pour définir talk comme un alias de bigTalk de B.

Modifier le contrôle d'accès de la méthode

L'utilisation de la syntaxe as peut également être utilisée pour ajuster le contrôle d'accès de la méthode.

Un exemple de modification du contrôle d'accès d'une méthode

Le code est le suivant :

<?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; }
}
?>

Composer trait à partir de trait

Tout comme les classes peuvent utiliser des traits, d'autres traits peuvent également utiliser des traits. En utilisant un ou plusieurs traits lorsqu'un trait est défini, il peut combiner tout ou partie des membres d'autres traits.

Un exemple de composition de traits à partir de traits

Le code est le suivant :

<?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();
?>

La routine ci-dessus affichera : Hello World !

Abstraction des membres des traits

Afin d'appliquer les exigences sur les classes utilisées, les traits prennent en charge l'utilisation de méthodes abstraites.

Indique un exemple d'application d'exigences via des méthodes abstraites

Le code est le suivant :

<?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;
    }
}
?>

Membre statique de Trait

Les traits peuvent être définis par des membres statiques et des méthodes statiques.

Un exemple de variable statique

Le code est le suivant :

<?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
?>

Un exemple de méthode statique

Le code est le suivant suit :

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

Exemples de variables statiques et de méthodes statiques

Le code est le suivant :

<?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
?>

Attributs
Le trait peut également définir des attributs .

Exemple de définition d'attributs

Le code est le suivant :

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

Si un trait définit un attribut, la classe ne pourra pas définir un attribut avec le même nom, sinon une erreur. Si la définition de la propriété dans la classe est compatible avec sa définition dans le trait (même visibilité et même valeur initiale) alors le niveau d'erreur est E_STRICT, sinon c'est une erreur fatale.

Exemples de conflits

Le code est le suivant :

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

Différences d'utilisation

Exemples de différentes utilisations

Le code est le suivant :

<?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
}
?>

La première utilisation est d'utiliser FooTest pour l'espace de noms, ce que l'on trouve est FooTest, la deuxième utilisation est d'utiliser un trait, quoi est trouvé estFooBarFooTest.

__CLASS__ et __TRAIT__
__CLASS__ renvoient le nom de classe du trait d'utilisation, __TRAIT__ renvoie le nom du trait

L'exemple est le suivant

Le code est le suivant :

<?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

L'exemple est le suivant

Le code est le suivant :

<?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;

Appel de la méthode trait

Bien que ce ne soit pas évident, si la méthode trait peut être définie comme une méthode statique dans une classe normale, elle peut être appelé

实例如下

代码如下:

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

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer