PHP バージョン 5.4.0 以降、PHP はコード再利用の新しい概念である Trait を提供します。 Trait は文字通り「特性」や「機能」を意味します。Trait キーワードを使用すると、PHP のクラスに新しい特性を追加できることがわかります。
オブジェクト指向に詳しい人なら誰でも、ソフトウェア開発で一般的に使用されるコードの再利用には継承とポリモーフィズムという 2 つの方法があることを知っています。 PHP では、単一継承のみを実現できます。特性はこれを回避します。以下、簡単な例で比較説明します。
現在、
Publish.php
と
Answer.php
の 2 つのクラスがあります。 LOG 関数を追加するには、クラス内のアクションを記録します。いくつかのオプションがあります:
継承
ポリモーフィズム
特性
図に示すように:
コード構造は次のとおりです:
// Log.php <?php Class Log { public function startLog() { // echo ... } public function endLog() { // echo ... } } // Publish.php <?php Class Publish extends Log { } // Answer.php <?php Class Answer extends Log { }
それがわかります継承は実際に要件を満たしています。しかし、これはオブジェクト指向の原則に違反します。 Publish や Answer and Log などの操作間の関係は、サブクラスと親クラス間の関係ではありません。したがって、この方法で使用することはお勧めできません。
図に示すように:
実装コード:
// Log.php <?php Interface Log { public function startLog(); public function endLog(); } // Publish.php <?php Class Publish implements Log { public function startLog() { // TODO: Implement startLog() method. } public function endLog() { // TODO: Implement endLog() method. } } // Answer.php <?php Class Answer implements Log { public function startLog() { // TODO: Implement startLog() method. } public function endLog() { // TODO: Implement endLog() method. } }
したがって、Publish アクションと Answer アクションではログの実装は同じである必要があります。 。明らかに、これは DRY (Don't Reply Yourself) 原則に違反しています。したがって、この方法で実装することはお勧めできません。
図に示すように:
実装コードは次のとおりです:
// Log.php <?php trait Log{ public function startLog() { // echo .. } public function endLog() { // echo .. } } // Publish.php <?php class Publish { use Log; } $publish = new Publish(); $publish->startLog(); $publish->endLog(); // Answer.php <?php class Answer { use Log; } $answer = new Answer(); $answer->startLog(); $answer->endLog();
ご覧のとおり、コードを複雑にすることなくコードの再利用を実現しました。
<?php class Publish { use Log; public function doPublish() { $this->publicF(); $this->protectF(); $this->privateF(); } } $publish = new Publish(); $publish->doPublish(); 执行上述代码输出结果如下: public function protected function private function
次のコードは、特性アプリケーションの属性の優先順位を証明するために使用されます:
<?php trait Log { public function publicF() { echo __METHOD__ . ' public function' . PHP_EOL; } protected function protectF() { echo __METHOD__ . ' protected function' . PHP_EOL; } } class Question { public function publicF() { echo __METHOD__ . ' public function' . PHP_EOL; } protected function protectF() { echo __METHOD__ . ' protected function' . PHP_EOL; } } class Publish extends Question { use Log; public function publicF() { echo __METHOD__ . ' public function' . PHP_EOL; } public function doPublish() { $this->publicF(); $this->protectF(); } } $publish = new Publish(); $publish->doPublish(); 上述代码的输出结果如下: Publish::publicF public function Log::protectF protected function
現在のクラスのメンバーは特性メソッドをオーバーライドします
特性は継承されたメソッドをオーバーライドします
クラスメンバーの優先順位は次のとおりです:
当前类>Trait>父类
<?php trait Log { public function startLog() { echo __METHOD__ . ' public function' . PHP_EOL; } protected function endLog() { echo __METHOD__ . ' protected function' . PHP_EOL; } } trait Check { public function parameterCheck($parameters) { // do sth } } class Publish extends Question { use Log,Check; public function doPublish($para) { $this->startLog(); $this->parameterCheck($para); $this->endLog(); } }
Insteadof
as
<?php trait Log { public function parameterCheck($parameters) { echo __METHOD__ . ' parameter check' . $parameters . PHP_EOL; } public function startLog() { echo __METHOD__ . ' public function' . PHP_EOL; } } trait Check { public function parameterCheck($parameters) { echo __METHOD__ . ' parameter check' . $parameters . PHP_EOL; } public function startLog() { echo __METHOD__ . ' public function' . PHP_EOL; } } class Publish { use Check, Log { Check::parameterCheck insteadof Log; Log::startLog insteadof Check; Check::startLog as csl; } public function doPublish() { $this->startLog(); $this->parameterCheck('params'); $this->csl(); } } $publish = new Publish(); $publish->doPublish();
Log::startLog public function Check::parameterCheck parameter checkparams Check::startLog public function
insteadof
as
Trait を参照するときは use キーワードが使用され、use キーワードは名前空間の参照にも使用されます。 2 つの違いは、Trait を参照するときにクラス内で使用されることです。