<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/language.oop5.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'zh',
  ),
  'this' => 
  array (
    0 => 'language.oop5.traits.php',
    1 => 'Trait',
    2 => 'Trait',
  ),
  'up' => 
  array (
    0 => 'language.oop5.php',
    1 => '类与对象',
  ),
  'prev' => 
  array (
    0 => 'language.oop5.interfaces.php',
    1 => '对象接口',
  ),
  'next' => 
  array (
    0 => 'language.oop5.anonymous.php',
    1 => '匿名类',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'zh',
    'path' => 'language/oop5/traits.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="language.oop5.traits" class="sect1">
  <h2 class="title">Trait</h2>
  <p class="para">
   PHP 实现了一种代码复用的方法，称为 trait。
  </p>
  <p class="para">
   Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait
   为了减少单继承语言的限制，使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait
   和 Class 组合的语义定义了一种减少复杂性的方式，避免传统多继承和 Mixin 类相关典型问题。
  </p>
  <p class="para">
   Trait 和 Class 相似，但仅仅旨在用细粒度和一致的方式来组合功能。
   无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合；也就是说，应用的几个 Class 之间不需要继承。
  </p>
  
  <div class="example" id="language.oop5.traits.basicexample">
    <p><strong>示例 #1 Trait 示例</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">TraitA </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayHello</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'Hello'</span><span style="color: #007700">;<br />    }<br />}<br /><br />trait </span><span style="color: #0000BB">TraitB </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayWorld</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'World'</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">MyHelloWorld<br /></span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">TraitA</span><span style="color: #007700">, </span><span style="color: #0000BB">TraitB</span><span style="color: #007700">; </span><span style="color: #FF8000">// A class can use multiple traits<br /><br />    </span><span style="color: #007700">public function </span><span style="color: #0000BB">sayHelloWorld</span><span style="color: #007700">() {<br />        </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayHello</span><span style="color: #007700">();<br />        echo </span><span style="color: #DD0000">' '</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayWorld</span><span style="color: #007700">();<br />        echo </span><span style="color: #DD0000">"!\n"</span><span style="color: #007700">;<br />    }<br />}<br /><br /></span><span style="color: #0000BB">$myHelloWorld </span><span style="color: #007700">= new </span><span style="color: #0000BB">MyHelloWorld</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$myHelloWorld</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayHelloWorld</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

    <div class="example-contents"><p>以上示例会输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Hello World!
</pre></div>
    </div>
   </div>
  
  <div class="sect2" id="language.oop5.traits.precedence">
   <h3 class="title">优先级</h3>
   <p class="para">
    从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了
    trait 的方法，而 trait 则覆盖了被继承的方法。
   </p>
   <div class="example" id="language.oop5.traits.precedence.examples.ex1">
    <p><strong>示例 #2 优先顺序示例</strong></p>
    <div class="example-contents"><p>
     从基类继承的成员被插入的 SayWorld Trait 中的 MyHelloWorld
     方法所覆盖。其行为 MyHelloWorld 类中定义的方法一致。优先顺序是当前类中的方法会覆盖
     trait 方法，而 trait 方法又覆盖了基类中的方法。
    </p></div>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">Base </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayHello</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'Hello '</span><span style="color: #007700">;<br />    }<br />}<br /><br />trait </span><span style="color: #0000BB">SayWorld </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayHello</span><span style="color: #007700">() {<br />        </span><span style="color: #0000BB">parent</span><span style="color: #007700">::</span><span style="color: #0000BB">sayHello</span><span style="color: #007700">();<br />        echo </span><span style="color: #DD0000">'World!'</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">MyHelloWorld </span><span style="color: #007700">extends </span><span style="color: #0000BB">Base </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">SayWorld</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$o </span><span style="color: #007700">= new </span><span style="color: #0000BB">MyHelloWorld</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayHello</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

    <div class="example-contents"><p>以上示例会输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Hello World!
</pre></div>
    </div>
   </div>
   <div class="example" id="language.oop5.traits.precedence.examples.ex2">
    <p><strong>示例 #3 另一个优先级顺序的例子</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">HelloWorld </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayHello</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'Hello World!'</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">TheWorldIsNotEnough </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">HelloWorld</span><span style="color: #007700">;<br />    public function </span><span style="color: #0000BB">sayHello</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'Hello Universe!'</span><span style="color: #007700">;<br />    }<br />}<br /><br /></span><span style="color: #0000BB">$o </span><span style="color: #007700">= new </span><span style="color: #0000BB">TheWorldIsNotEnough</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayHello</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

    <div class="example-contents"><p>以上示例会输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Hello Universe!
</pre></div>
    </div>
   </div>
  </div>
  
  <div class="sect2" id="language.oop5.traits.multiple">
   <h3 class="title">多个 trait</h3>
   <p class="para">
    通过逗号分隔，在 <code class="literal">use</code> 声明列出多个 trait，可以都插入到一个类中。
   </p>
   <div class="example" id="language.oop5.traits.multiple.ex1">
    <p><strong>示例 #4 多个 trait 的用法</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">Hello </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayHello</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'Hello '</span><span style="color: #007700">;<br />    }<br />}<br /><br />trait </span><span style="color: #0000BB">World </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayWorld</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'World'</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">MyHelloWorld </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">Hello</span><span style="color: #007700">, </span><span style="color: #0000BB">World</span><span style="color: #007700">;<br />    public function </span><span style="color: #0000BB">sayExclamationMark</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'!'</span><span style="color: #007700">;<br />    }<br />}<br /><br /></span><span style="color: #0000BB">$o </span><span style="color: #007700">= new </span><span style="color: #0000BB">MyHelloWorld</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayHello</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayWorld</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayExclamationMark</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

    <div class="example-contents"><p>以上示例会输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Hello World!
</pre></div>
    </div>
   </div>
  </div>
  
  <div class="sect2" id="language.oop5.traits.conflict">
   <h3 class="title">冲突的解决</h3>
   <p class="para">
    如果两个 trait 都插入了一个同名的方法，如果没有明确解决冲突将会产生一个致命错误。
   </p>
   <p class="para">
    为了解决多个 trait 在同一个类中的命名冲突，需要使用 <code class="literal">insteadof</code>
    操作符来明确指定使用冲突方法中的哪一个。
   </p>
   <p class="para">
    以上方式仅允许排除掉其它方法，<code class="literal">as</code> 操作符可以
    为某个方法引入别名。
    注意，<code class="literal">as</code> 操作符不会对方法进行重命名，也不会影响其方法。
   </p>
   <div class="example" id="language.oop5.traits.conflict.ex1">
    <p><strong>示例 #5 冲突的解决</strong></p>
    <div class="example-contents"><p>
      在本例中 Talker 使用了 trait A 和 B。由于 A 和 B
      有冲突的方法，其定义了使用 trait B 中的 smallTalk 以及 trait A 中的 bigTalk。
    </p></div>
    <div class="example-contents"><p>
     Aliased_Talker 使用了 <code class="literal">as</code> 操作符来定义了 <code class="literal">talk</code>
     来作为 B 的 bigTalk 的别名。
    </p></div> 
    <div class="example-contents">
<div class="annotation-non-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">smallTalk</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'a'</span><span style="color: #007700">;<br />    }<br />    public function </span><span style="color: #0000BB">bigTalk</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'A'</span><span style="color: #007700">;<br />    }<br />}<br /><br />trait </span><span style="color: #0000BB">B </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">smallTalk</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'b'</span><span style="color: #007700">;<br />    }<br />    public function </span><span style="color: #0000BB">bigTalk</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'B'</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">Talker </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">A</span><span style="color: #007700">, </span><span style="color: #0000BB">B </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">B</span><span style="color: #007700">::</span><span style="color: #0000BB">smallTalk </span><span style="color: #007700">insteadof </span><span style="color: #0000BB">A</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">A</span><span style="color: #007700">::</span><span style="color: #0000BB">bigTalk </span><span style="color: #007700">insteadof </span><span style="color: #0000BB">B</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">Aliased_Talker </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">A</span><span style="color: #007700">, </span><span style="color: #0000BB">B </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">B</span><span style="color: #007700">::</span><span style="color: #0000BB">smallTalk </span><span style="color: #007700">insteadof </span><span style="color: #0000BB">A</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">A</span><span style="color: #007700">::</span><span style="color: #0000BB">bigTalk </span><span style="color: #007700">insteadof </span><span style="color: #0000BB">B</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">B</span><span style="color: #007700">::</span><span style="color: #0000BB">bigTalk </span><span style="color: #007700">as </span><span style="color: #0000BB">talk</span><span style="color: #007700">;<br />    }<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

   </div>
  </div>
  
  <div class="sect2" id="language.oop5.traits.visibility">
   <h3 class="title">修改方法的访问控制</h3>
   <p class="para">
    使用 <code class="literal">as</code> 语法还可以用来调整方法的访问控制。
   </p>
   <div class="example" id="language.oop5.traits.visibility.ex1">
    <p><strong>示例 #6 修改方法的访问控制</strong></p>
    <div class="example-contents">
<div class="annotation-non-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">HelloWorld </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayHello</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'Hello World!'</span><span style="color: #007700">;<br />    }<br />}<br /><br /></span><span style="color: #FF8000">// 修改 sayHello 的访问控制<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">MyClass1 </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">HelloWorld </span><span style="color: #007700">{ </span><span style="color: #0000BB">sayHello </span><span style="color: #007700">as protected; }<br />}<br /><br /></span><span style="color: #FF8000">// 给方法一个改变了访问控制的别名<br />// 原版 sayHello 的访问控制则没有发生变化<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">MyClass2 </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">HelloWorld </span><span style="color: #007700">{ </span><span style="color: #0000BB">sayHello </span><span style="color: #007700">as private </span><span style="color: #0000BB">myPrivateHello</span><span style="color: #007700">; }<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

   </div>
  </div>
  
  <div class="sect2" id="language.oop5.traits.composition">
   <h3 class="title">从 trait 来组成 trait</h3>
   <p class="para">
    正如 class 能够使用 trait 一样，其它 trait 也能够使用 trait。在 trait
    定义时通过使用一个或多个 trait，能够组合其它 trait 中的部分或全部成员。
   </p>
   <div class="example" id="language.oop5.traits.composition.ex1">
    <p><strong>示例 #7 从 trait 来组成 trait</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">Hello </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayHello</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'Hello '</span><span style="color: #007700">;<br />    }<br />}<br /><br />trait </span><span style="color: #0000BB">World </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayWorld</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'World!'</span><span style="color: #007700">;<br />    }<br />}<br /><br />trait </span><span style="color: #0000BB">HelloWorld </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">Hello</span><span style="color: #007700">, </span><span style="color: #0000BB">World</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">MyHelloWorld </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">HelloWorld</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$o </span><span style="color: #007700">= new </span><span style="color: #0000BB">MyHelloWorld</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayHello</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sayWorld</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

    <div class="example-contents"><p>以上示例会输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Hello World!
</pre></div>
    </div>
   </div>
  </div>
  
  <div class="sect2" id="language.oop5.traits.abstract">
   <h3 class="title">Trait 的抽象成员</h3>
   <p class="para">
    为了对使用的类施加强制要求，trait 支持抽象方法的使用。
    支持 public 、protected 和 private 方法。PHP 8.0.0 之前，
    仅支持 public 和 protected 抽象方法。
   </p>
   <div class="caution"><strong class="caution">警告</strong>
    <p class="simpara">
     自 PHP 8.0.0 起，具体方法的签名必须遵循<a href="language.oop5.basic.php#language.oop.lsp" class="link">签名兼容性规则</a>。以前，其签名可能有所不同。
    </p>
   </div>
   <div class="example" id="language.oop5.traits.abstract.ex1">
    <p><strong>示例 #8 表示通过抽象方法来进行强制要求</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">Hello </span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">sayHelloWorld</span><span style="color: #007700">() {<br />        echo </span><span style="color: #DD0000">'Hello'</span><span style="color: #007700">.</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getWorld</span><span style="color: #007700">();<br />    }<br />    abstract public function </span><span style="color: #0000BB">getWorld</span><span style="color: #007700">();<br />}<br /><br />class </span><span style="color: #0000BB">MyHelloWorld </span><span style="color: #007700">{<br />    private </span><span style="color: #0000BB">$world</span><span style="color: #007700">;<br />    use </span><span style="color: #0000BB">Hello</span><span style="color: #007700">;<br />    public function </span><span style="color: #0000BB">getWorld</span><span style="color: #007700">() {<br />        return </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">world</span><span style="color: #007700">;<br />    }<br />    public function </span><span style="color: #0000BB">setWorld</span><span style="color: #007700">(</span><span style="color: #0000BB">$val</span><span style="color: #007700">) {<br />        </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">world </span><span style="color: #007700">= </span><span style="color: #0000BB">$val</span><span style="color: #007700">;<br />    }<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

   </div>
  </div>
  
  <div class="sect2" id="language.oop5.traits.static">
   <h3 class="title">Trait 的静态成员</h3>
   <p class="para">
    Traits 可以定义静态变量、静态方法和静态属性。
   </p>
   <blockquote class="note"><p><strong class="note">注意</strong>: 
    <p class="para">
     自 PHP 8.1.0 起，弃用直接在 trait 上调用静态方法或者访问静态属性。
     静态方法和属性应该仅在使用了 trait 的 class 中访问。
    </p>
   </p></blockquote>
   <div class="example" id="language.oop5.traits.static.ex1">
    <p><strong>示例 #9 静态变量</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">Counter<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">inc</span><span style="color: #007700">()<br />    {<br />        static </span><span style="color: #0000BB">$c </span><span style="color: #007700">= </span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />        </span><span style="color: #0000BB">$c </span><span style="color: #007700">= </span><span style="color: #0000BB">$c </span><span style="color: #007700">+ </span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />        echo </span><span style="color: #DD0000">"</span><span style="color: #0000BB">$c</span><span style="color: #DD0000">\n"</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">C1<br /></span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">Counter</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">C2<br /></span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">Counter</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$o </span><span style="color: #007700">= new </span><span style="color: #0000BB">C1</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">inc</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$p </span><span style="color: #007700">= new </span><span style="color: #0000BB">C2</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$p</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">inc</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

    <div class="example-contents"><p>以上示例会输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
1
1
</pre></div>
    </div>
   </div>
   <div class="example" id="language.oop5.traits.static.ex2">
    <p><strong>示例 #10 静态方法</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">StaticExample<br /></span><span style="color: #007700">{<br />    public static function </span><span style="color: #0000BB">doSomething</span><span style="color: #007700">()<br />    {<br />        return </span><span style="color: #DD0000">'Doing something'</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">Example<br /></span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">StaticExample</span><span style="color: #007700">;<br />}<br /><br />echo </span><span style="color: #0000BB">Example</span><span style="color: #007700">::</span><span style="color: #0000BB">doSomething</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

    <div class="example-contents"><p>以上示例会输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Doing something
</pre></div>
    </div>
   </div>
   <div class="example" id="language.oop5.traits.static.ex3">
    <p><strong>示例 #11 静态属性</strong></p>
    <div class="caution"><strong class="caution">警告</strong>
     <p class="simpara">
      PHP 8.3.0 之前，trait 中定义的静态属性会在使用该 trait 的同一继承层次结构中的所有类之间共享。自
      PHP 8.3.0 起，如果子类使用具有静态属性的 trait，将视为与父类中定义的 trait 不同。
     </p>
    </div>
    <div class="example-contents">
     <div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">T<br /></span><span style="color: #007700">{<br />    public static </span><span style="color: #0000BB">$counter </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">A<br /></span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">T</span><span style="color: #007700">;<br /><br />    public static function </span><span style="color: #0000BB">incrementCounter</span><span style="color: #007700">()<br />    {<br />        static::</span><span style="color: #0000BB">$counter</span><span style="color: #007700">++;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">B </span><span style="color: #007700">extends </span><span style="color: #0000BB">A<br /></span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">T</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">A</span><span style="color: #007700">::</span><span style="color: #0000BB">incrementCounter</span><span style="color: #007700">();<br /><br />echo </span><span style="color: #0000BB">A</span><span style="color: #007700">::</span><span style="color: #0000BB">$counter</span><span style="color: #007700">, </span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />echo </span><span style="color: #0000BB">B</span><span style="color: #007700">::</span><span style="color: #0000BB">$counter</span><span style="color: #007700">, </span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

    <div class="example-contents"><p>以上示例在 PHP 8.3 中的输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
2
1
</pre></div>
    </div>
   </div>
  </div>
  
  <div class="sect2" id="language.oop5.traits.properties">
   <h3 class="title">属性</h3>
   <p class="para">
    Trait 同样可以定义属性。
   </p>
   <div class="example" id="language.oop5.traits.properties.example">
    <p><strong>示例 #12 定义属性</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">PropertiesTrait<br /></span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">$x </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">PropertiesExample<br /></span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">PropertiesTrait</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$example </span><span style="color: #007700">= new </span><span style="color: #0000BB">PropertiesExample</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$example</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">x</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

   </div>
   <p class="para">
    Trait 定义了一个属性后，类就不能定义同样名称的属性，否则会产生 fatal error。
    有种情况例外：属性是兼容的（同样的访问可见度、类型、readonly 修饰符和初始默认值）。
   </p>
   <div class="example" id="language.oop5.traits.properties.conflicts">
    <p><strong>示例 #13 解决冲突</strong></p>
    <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">PropertiesTrait </span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">$same </span><span style="color: #007700">= </span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">$different1 </span><span style="color: #007700">= </span><span style="color: #0000BB">false</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">bool $different2</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">bool $different3</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">PropertiesExample </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">PropertiesTrait</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">$same </span><span style="color: #007700">= </span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />    public </span><span style="color: #0000BB">$different1 </span><span style="color: #007700">= </span><span style="color: #0000BB">true</span><span style="color: #007700">; </span><span style="color: #FF8000">// Fatal error<br />    </span><span style="color: #007700">public </span><span style="color: #0000BB">string $different2</span><span style="color: #007700">; </span><span style="color: #FF8000">// Fatal error<br />    </span><span style="color: #007700">readonly protected </span><span style="color: #0000BB">bool $different3</span><span style="color: #007700">; </span><span style="color: #FF8000">// Fatal error<br /></span><span style="color: #007700">}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
    </div>

   </div>
  </div>

 <div class="sect2" id="language.oop5.traits.constants">
  <h3 class="title">常量</h3>
  <p class="para">
   自 PHP 8.2.0 起，trait 也可以定义常量。
  </p>
  <div class="example" id="language.oop5.traits.constants.example">
   <p><strong>示例 #14 定义常量</strong></p>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">ConstantsTrait </span><span style="color: #007700">{<br />    public const </span><span style="color: #0000BB">FLAG_MUTABLE </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />    final public const </span><span style="color: #0000BB">FLAG_IMMUTABLE </span><span style="color: #007700">= </span><span style="color: #0000BB">5</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">ConstantsExample </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">ConstantsTrait</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$example </span><span style="color: #007700">= new </span><span style="color: #0000BB">ConstantsExample</span><span style="color: #007700">;<br />echo </span><span style="color: #0000BB">$example</span><span style="color: #007700">::</span><span style="color: #0000BB">FLAG_MUTABLE</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

    <div class="example-contents"><p>以上示例会输出：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
1
</pre></div>
    </div>
  </div>
  <p class="para">
   如果 trait 定义了常量，然后类不能定义相同名称的常量，除非两者兼容（相同的可见性、初始化值和
   final），否则会发出 fatal error。
  </p>
  <div class="example" id="language.oop5.traits.constants.conflicts">
   <p><strong>示例 #15 解决冲突</strong></p>
   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">ConstantsTrait </span><span style="color: #007700">{<br />    public const </span><span style="color: #0000BB">FLAG_MUTABLE </span><span style="color: #007700">= </span><span style="color: #0000BB">1</span><span style="color: #007700">;<br />    final public const </span><span style="color: #0000BB">FLAG_IMMUTABLE </span><span style="color: #007700">= </span><span style="color: #0000BB">5</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">ConstantsExample </span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">ConstantsTrait</span><span style="color: #007700">;<br />    public const </span><span style="color: #0000BB">FLAG_IMMUTABLE </span><span style="color: #007700">= </span><span style="color: #0000BB">5</span><span style="color: #007700">; </span><span style="color: #FF8000">// Fatal error<br /></span><span style="color: #007700">}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>
 </div>

 <div class="sect2" id="language.oop5.traits.final-methods">
  <h3 class="title">final 方法</h3>
  <p class="simpara">
   自 PHP 8.3.0 起，<a href="language.oop5.final.php" class="link">final</a> 修饰符可以应用于使用
   <code class="literal">as</code> 操作符从 trait 导入的方法。这可用于防止子类覆盖该方法。但是，使用该 trait
   的类仍然可以覆盖该方法。
  </p>
  <div class="example" id="language.oop5.traits.final-methods.example">
   <p><strong>示例 #16 将来自 trait 的方法定义为 <code class="literal">final</code></strong></p>
   <div class="example-contents">
    <div class="annotation-interactive phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">trait </span><span style="color: #0000BB">CommonTrait<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">method</span><span style="color: #007700">()<br />    {<br />        echo </span><span style="color: #DD0000">'Hello'</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">FinalExampleA<br /></span><span style="color: #007700">{<br />    use </span><span style="color: #0000BB">CommonTrait </span><span style="color: #007700">{<br />        </span><span style="color: #0000BB">CommonTrait</span><span style="color: #007700">::</span><span style="color: #0000BB">method </span><span style="color: #007700">as final; </span><span style="color: #FF8000">// 'final' 防止子类覆盖方法<br />    </span><span style="color: #007700">}<br />}<br /><br />class </span><span style="color: #0000BB">FinalExampleB </span><span style="color: #007700">extends </span><span style="color: #0000BB">FinalExampleA<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">method</span><span style="color: #007700">() {}<br />}<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

    <div class="example-contents"><p>以上示例的输出类似于：</p></div>
    <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Fatal error: Cannot override final method FinalExampleA::method() in ...
</pre></div>
    </div>
  </div>
 </div>

 </div><?php manual_footer($setup); ?>