yii2のソースコードを読んでいるときにtraitに出会ったので、勉強して記録としてブログを書きました。
PHP 5.4.0 以降、PHP は traits と呼ばれるコード再利用の方法を実装しています。
Traits は、PHP のような単一継承言語用に用意されたコード再利用メカニズムです。トレイトは、単一継承言語の制約を軽減し、開発者が異なる階層内の独立したクラスでメソッド セットを自由に再利用できるように設計されています。特性とクラス構成のセマンティクスは、複雑さを軽減し、従来の多重継承とミックスインに関連する典型的な問題を回避する方法を定義します。
Trait はクラスに似ていますが、きめ細かく一貫した方法で機能を組み合わせるようにのみ設計されています。特性を単独でインスタンス化することはできません。これは、従来の継承に水平機能の組み合わせを追加します。つまり、アプリケーション クラスのメンバーを継承する必要がありません。
特性の例
コードは次のとおりです:
特性 ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
ezcReflectionReturnInfo を使用します;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
ezcReflectionReturnInfo を使用します;
/* ... */
}
?>
優先度
基本クラスから継承されたメンバーは、トレイトによって挿入されたメンバーによってオーバーライドされます。優先順位は、現在のクラスのメンバーがトレイトのメソッドをオーバーライドし、トレイトが継承されたメソッドをオーバーライドすることです。
優先順位付けの例
コードは次のとおりです:
クラスベース{
パブリック関数sayHello() {
エコー「こんにちは」;
}
}
特性 SayWorld {
パブリック関数sayHello() {
親::sayHello();
エコー「ワールド!」;
}
}
class MyHelloWorld extends Base {
SayWorld を使用します;
}
$o = 新しい MyHelloWorld();
$o->sayHello();
?>
上記のルーチンは次のように出力します: Hello World!
基本クラスから継承されたメンバーは、挿入された SayWorld トレイトの SayHello メソッドによってオーバーライドされます。その動作は、MyHelloWorld クラスで定義されたメソッドと一致しています。優先順位としては、現在のクラスのメソッドが特性メソッドをオーバーライドし、特性メソッドが基本クラスのメソッドをオーバーライドします。
優先順位の別の例
コードは次のとおりです:
特性 HelloWorld {
パブリック関数sayHello() {
「Hello World!」をエコーします;
}
}
クラス TheWorldIsNotEnough {
HelloWorld を使用します;
パブリック関数sayHello() {
echo 'Hello Universe!';
}
}
$o = 新しいTheWorldIsNotEnough();
$o->sayHello();
?>
上記のルーチンは次のように出力します: Hello Universe!
複数の特性
カンマで区切って use ステートメントに複数の特性をリストすると、それらをクラスに挿入できます。
複数の特性の使用例
コードは次のとおりです:
特性 こんにちは{
パブリック関数sayHello() {
エコー「こんにちは」;
}
}
特性ワールド{
パブリック関数sayWorld() {
エコー「ワールド」;
}
}
クラス MyHelloWorld {
Hello, World を使用します。
パブリック関数sayExclamationMark() {
エコー「!」;
}
}
$o = 新しい MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>
上記のルーチンは次のように出力します: Hello World!
紛争解決
2 つのトレイトが同じ名前のメソッドを挿入した場合、競合が明示的に解決されないと致命的なエラーが発生します。
同じクラス内の複数のトレイトの名前の競合を解決するには、 replaceof 演算子を使用して、競合するメソッドのどれを使用するかを明示的に指定する必要があります。
上記のメソッドでは、他のメソッドを除外することのみが可能です。as 演算子は、競合するメソッドの 1 つを別の名前で導入できます。
紛争解決の例
コードは次のとおりです:
特性 A {
パブリック関数 smallTalk() {
エコー「a」;
}
パブリック関数 bigTalk() {
エコー「A」;
}
}
特性 B {
パブリック関数 smallTalk() {
エコー「b」;
}
パブリック関数 bigTalk() {
エコー「B」;
}
}
クラストーカー{
A、Bを使用します{
A の代わりに B::smallTalk を使用します;
B の代わりに A::bigTalk を使用します。
}
}
クラス Aliased_Talker {
A、Bを使用します{
A の代わりに B::smallTalk を使用します;
B の代わりに A::bigTalk を使用します。
B::bigTalk はトークとして;
}
}
?>
この例では、トーカーは特性 A と B を使用します。 A と B は競合するメソッドを持っているため、トレイト B の smallTalk とトレイト A の bigTalk を使用することを定義します。
Aliased_Talker は、as 演算子を使用して、トークを B の bigTalk のエイリアスとして定義します。
メソッドのアクセス制御を変更する
as 構文を使用して、メソッドのアクセス制御を調整することもできます。
メソッドアクセス制御の変更例
コードは次のとおりです:
特性 HelloWorld {
パブリック関数sayHello() {
「Hello World!」をエコーします;
}
}
//sayHello
のアクセス制御を変更します
クラス MyClass1 {
HelloWorld {sayHello を保護として使用します。
}
//アクセス制御を変更するエイリアスをメソッドに与えます
// 元のsayHelloのアクセス制御は変更されていません
クラス MyClass2 {
HelloWorld {sayHello をプライベート myPrivateHello として使用します
;
}
?>
特性から特性を構成する
クラスが特性を使用できるのと同じように、他の特性も特性を使用できます。特性を定義するときに 1 つ以上の特性を使用すると、他の特性の一部またはすべてのメンバーを組み合わせることができます。
特性から特性を形成する例
コードは次のとおりです:
特性 こんにちは{
パブリック関数sayHello() {
エコー「こんにちは」;
}
}
特性ワールド{
パブリック関数sayWorld() {
エコー「ワールド!」;
}
}
特性 HelloWorld {
Hello, World を使用します。
}
クラス MyHelloWorld {
HelloWorld を使用します;
}
$o = 新しい MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>
上記のルーチンは次のように出力します: Hello World!
Traitの抽象メンバー
使用されるクラスに要件を強制するために、トレイトは抽象メソッドの使用をサポートします。
抽象メソッドを使用して要件を強制する例を示します
コードは次のとおりです:
特性 こんにちは{
パブリック関数sayHelloWorld() {
echo 'Hello'.$this->getWorld();
}
抽象パブリック関数 getWorld();
}
クラス MyHelloWorld {
プライベート $world;
こんにちはを使用してください;
パブリック関数 getWorld() {
$this->world;
を返す
}
パブリック関数 setWorld($val) {
$this->world = $val;
}
}
?>
Trait の静的メンバー
特性は静的メンバーと静的メソッドによって定義できます。
静的変数の例
コードは次のとおりです:
特性カウンター{
パブリック関数 inc() {
静的 $c = 0;
$c = $c + 1;
エコー "$cn";
}
}
クラス C1 {
カウンターを使用します;
}
クラス C2 {
カウンターを使用します;
}
$o = new C1() $o->inc(); // エコー 1
;
$p = new C2(); // エコー 1
;
?>
静的メソッドの例
コードは次のとおりです:
特性 StaticExample {
パブリック静的関数 doSomething() {
return '何かをしています';
}
}
クラスの例 {
StaticExample を使用します;
}
例::doSomething();
?>
静的変数と静的メソッドの例
コードは次のとおりです:
特性カウンター{
パブリック静的 $c = 0;
パブリック静的関数 inc() {
self::$c = self::$c + 1;
エコー self::$c . "n";
}
}
クラス C1 {
カウンターを使用します;
}
クラス C2 {
カウンターを使用します;
}
C1::inc() // エコー 1
;
C2::inc() // エコー 1
;
?>
プロパティ
特性によってプロパティを定義することもできます。
属性の定義例
コードは次のとおりです:
特性プロパティTrait {
パブリック $x = 1;
}
class PropertiesExample {
PropertiesTrait を使用します;
}
$example = 新しいプロパティの例;
$example->x;
?>
トレイトがプロパティを定義する場合、クラスは同じ名前のプロパティを定義できません。定義しない場合はエラーが生成されます。クラス内のプロパティの定義が特性内のその定義と互換性がある (可視性と初期値が同じ) 場合、エラー レベルは E_STRICT であり、そうでない場合は致命的エラーです。
競合の例
コードは次のとおりです:
特性プロパティTrait {
public $same = true;
パブリック $異なる = false;
}
class PropertiesExample {
PropertiesTrait を使用します;
public $same = true // 厳格な基準
;
public $ Different = true // 致命的なエラー
;
}
?>
使用上の違い
さまざまな使用例
コードは次のとおりです:
名前空間 FooBar;
use FooTest; // FooTest を意味します - イニシャルはオプションです
?>
名前空間 FooBar;
クラス SomeClass {
use FooTest; // は FooBarFooTest を意味します
}
?>
最初の使用法は名前空間に FooTest を使用し、FooTest が見つかります。2 番目の使用法はトレイトを使用することで、FooBarFooTest が見つかります。
__CLASS__ と __TRAIT__
__CLASS__ は使用トレイトのクラス名を返し、__TRAIT__ はトレイト名を返します
例は以下の通りです
コードは次のとおりです:
特性 TestTrait {
パブリック関数 testMethod() {
echo "クラス: " . PHP_EOL;
echo "特性: " . __TRAIT__ .
}
}
クラスBaseClass {
TestTrait を使用します;
}
クラス TestClass は BaseClass を拡張します {
}
$t = 新しい TestClass();
$t->testMethod();
//クラス: BaseClass
// 特性: TestTrait
トレイトシングルトン
例は以下の通りです
コードは次のとおりです:
特性シングルトン {
/**
* プライベート構造。通常はクラスを使用して定義されます
*/
//プライベート関数 __construct() {}
パブリック静的関数 getInstance() {
静的 $_instance = NULL;
$class = __CLASS__;
$_instance を返す ?: $_instance = 新しい $class;
}
パブリック関数 __clone() {
trigger_error('「.__CLASS__.」のクローン作成は許可されていません。',E_USER_ERROR);
}
パブリック関数 __wakeup() {
trigger_error('「.__CLASS__.」のシリアル化解除は許可されていません。',E_USER_ERROR);
}
}
/**
*使用例
*/
クラス foo {
シングルトンを使用します;
プライベート関数 __construct() {
$this->name = 'foo';
}
}
クラスバー{
シングルトンを使用します;
プライベート関数 __construct() {
$this->name = 'バー';
}
}
$foo = foo::getInstance();
echo $foo->name;
$bar = bar::getInstance();
echo $bar->name;
特性メソッドを呼び出す
明らかではありませんが、Traitメソッドを通常のクラスで静的メソッドとして定義できれば呼び出すことができます
例は以下の通りです
コードは次のとおりです:
特性 Foo {
関数 bar() {
「バズ」を返します。
}
}
echo Foo::bar(),"\n";
?>
特性の新しい機能についてご存知ですか? この記事がお役に立てば幸いです。
http://www.bkjia.com/PHPjc/966917.html
www.bkjia.com
truehttp://www.bkjia.com/PHPjc/966917.html技術記事 PHP でコードの再利用を実装する方法。この記事では、PHP でコードの再利用を実装する方法を主に紹介します。必要な方は、こちらを参照してください。
声明:この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。