PHP は、コードの再利用を実現する方法です。新しい機能、新しい機能
yii2のソースコードを読んでいるときにtraitに出会ったので、勉強して記録としてブログを書きました。
PHP 5.4.0 以降、PHP は traits と呼ばれるコード再利用の方法を実装しています。
Traits は、PHP のような単一継承言語用に用意されたコード再利用メカニズムです。トレイトは、単一継承言語の制約を軽減し、開発者が異なる階層内の独立したクラスでメソッド セットを自由に再利用できるように設計されています。特性とクラス構成のセマンティクスは、複雑さを軽減し、従来の多重継承とミックスインに関連する典型的な問題を回避する方法を定義します。
Trait はクラスに似ていますが、きめ細かく一貫した方法で機能を組み合わせるようにのみ設計されています。特性を単独でインスタンス化することはできません。これは、従来の継承に水平機能の組み合わせを追加します。つまり、アプリケーション クラスのメンバーを継承する必要がありません。
特性の例
コードをコピーします コードは次のとおりです:
特性 ezcReflectionReturnInfo {
関数 getReturnType() { /*1*/ }
関数 getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
ezcReflectionReturnInfo を使用します;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
ezcReflectionReturnInfo を使用します;
/* ... */
}
?>
優先
基本クラスから継承されたメンバーは、トレイトによって挿入されたメンバーによってオーバーライドされます。優先順位は、現在のクラスのメンバーがトレイトのメソッドをオーバーライドし、トレイトが継承されたメソッドをオーバーライドすることです。
優先順位付けの例
コードをコピーします コードは次のとおりです:
クラスベース{
パブリック関数sayHello() {
エコー「こんにちは」;
}
}
特性 SayWorld {
パブリック関数sayHello() {
parent::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() {
return $this->world;
}
パブリック関数 setWorld($val) {
$this->world = $val;
}
}
?>
Trait の静的メンバー
特性は静的メンバーと静的メソッドによって定義できます。
静的変数の例
コードをコピーします コードは次のとおりです:
特性カウンター{
パブリック関数 inc() {
静的 $c = 0;
$c = $c + 1;
echo "$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;
echo self::$c . "n";
}
}
クラス C1 {
カウンターを使用する;
}
クラス C2 {
カウンターを使用する;
}
C1::inc() // エコー 1
;
C2::inc() // エコー 1
;
?>
プロパティ
特性によってプロパティを定義することもできます。
属性の定義例
コードをコピーします コードは次のとおりです:
特性プロパティTrait {
パブリック $x = 1;
}
class PropertiesExample {
PropertiesTrait を使用します;
}
$example = 新しいプロパティの例;
$example->x;
?>
トレイトがプロパティを定義する場合、クラスは同じ名前のプロパティを定義できません。定義しない場合はエラーが生成されます。クラス内のプロパティの定義が特性内の定義と互換性がある (可視性と初期値が同じ) 場合、エラー レベルは E_STRICT であり、そうでない場合は致命的エラーです。
競合の例
コードをコピーします コードは次のとおりです:
特性プロパティTrait {
パブリック $same = true;
パブリック $異なる = false;
}
class PropertiesExample {
PropertiesTrait を使用します;
パブリック $same = true // 厳格な基準
;
Public $ Different = true // 致命的なエラー
;
}
?>
使用上の違い
さまざまな使用例
コードをコピーします コードは次のとおりです:
名前空間 FooBar;
use FooTest; // FooTest を意味します - イニシャルはオプションです
?>
名前空間 FooBar;
クラス SomeClass {
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() {
static $_instance = NULL;
$class = __CLASS__;
return $_instance ?: $_instance = new $class;
}
パブリック関数 __clone() {
trigger_error('「.__CLASS__.」のクローン作成は許可されていません。',E_USER_ERROR);
}
パブリック関数 __wakeup() {
trigger_error('「.__CLASS__.」のシリアル化解除は許可されていません。',E_USER_ERROR);
}
}
/**
*使用例
*/
クラス foo {
シングルトンを使用します;
プライベート関数 __construct() {
$this->name = 'foo';
}
}
クラスバー{
シングルトンを使用します;
プライベート関数 __construct() {
$this->name = 'bar';
}
}
$foo = foo::getInstance();
echo $foo->name;
$bar = bar::getInstance();
echo $bar->name;
特性メソッドを呼び出す
明らかではありませんが、Traitメソッドを通常のクラスで静的メソッドとして定義できれば呼び出すことができます
例は以下の通りです
コードをコピーします コードは次のとおりです:
特性 Foo {
関数バー() {
'baz' を返します
}
}
echo Foo::bar(),"\n";
?>
特性の新しい機能についてご存知ですか? この記事がお役に立てば幸いです。
http://www.bkjia.com/PHPjc/959108.html
www.bkjia.comtruehttp://www.bkjia.com/PHPjc/959108.html技術記事 PHP でコードの再利用を実現する 1 つの方法は、トレイトの新機能です。 yii2 のソース コードを読んでいるときにトレイトの新機能を見つけたので、それを調べて記録するためにブログを書きました。 PHP 5.4 以降...