<?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.inheritance.php',
    1 => '对象继承',
    2 => '对象继承',
  ),
  'up' => 
  array (
    0 => 'language.oop5.php',
    1 => '类与对象',
  ),
  'prev' => 
  array (
    0 => 'language.oop5.visibility.php',
    1 => '访问控制（可见性）',
  ),
  'next' => 
  array (
    0 => 'language.oop5.paamayim-nekudotayim.php',
    1 => '范围解析操作符 （::）',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'zh',
    'path' => 'language/oop5/inheritance.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="language.oop5.inheritance" class="sect1">
 <h2 class="title">对象继承</h2>
 <p class="para">
  继承已为大家所熟知的一个程序设计特性，PHP 的对象模型也使用了继承。继承将会影响到类与类，对象与对象之间的关系。
 </p>
 <p class="para">
  比如，当扩展一个类，子类就会继承父类所有 public 和 protected 的方法，属性和常量。除非子类覆盖了父类的方法，被继承的方法都会保留其原有功能。
 </p>
 <p class="para">
  继承有助于功能的设计和抽象，在实现类似的对象、增加新功能时，无须重复编写这些公用的功能。
 </p>
  <p class="para">
   子类无法访问父类的私有方法。因此，子类无需考虑正常的继承规则而重新实现私有方法。
   然而，在 PHP 8.0.0 之前， <code class="literal">final</code> 和 <code class="literal">static</code>
   的限制会应用于 private 方法。
   从 PHP 8.0.0 开始，仅 <code class="literal">private final</code> 的构造器是唯一受限的 private 方法；
   想要“禁用”构造器，我们通常用静态工厂方法作为代替。
  </p>
 <p class="para">
  方法，属性和常量的 <a href="language.oop5.visibility.php" class="link">可见性</a>
  可以放宽，例如 <code class="literal">protected</code> 方法可以标记为 <code class="literal">public</code>，
  但不能增加限制，例如标记 <code class="literal">public</code> 属性为 <code class="literal">private</code>。有个例外是构造方法，可以限制其可见性，例如
  <code class="literal">public</code> 构造方法可以在子类中标记为 <code class="literal">private</code>。
 </p>

 <blockquote class="note"><p><strong class="note">注意</strong>: 
  <p class="para">
   除非使用了自动加载，否则一个类必须在使用之前被定义。如果一个类扩展了另一个，则父类必须在子类之前被声明。此规则适用于类继承其它类与接口。
  </p>
 </p></blockquote>
 <blockquote class="note"><p><strong class="note">注意</strong>: 
  <p class="para">
   不允许使用<a href="language.oop5.properties.php#language.oop5.properties.readonly-properties" class="link">只读属性</a>覆盖可读写属性，反之亦然。
    <div class="informalexample">
     <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">class </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br />    public </span><span style="color: #0000BB">int $prop</span><span style="color: #007700">;<br />}<br />class </span><span style="color: #0000BB">B </span><span style="color: #007700">extends </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br />    </span><span style="color: #FF8000">// Illegal: read-write -&gt; readonly<br />    </span><span style="color: #007700">public readonly </span><span style="color: #0000BB">int $prop</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
     </div>

    </div>
   </p>
  </p></blockquote>

 <div class="example" id="example-1">
  <p><strong>示例 #1 继承示例</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">class </span><span style="color: #0000BB">Foo<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">printItem</span><span style="color: #007700">(</span><span style="color: #0000BB">$string</span><span style="color: #007700">)<br />    {<br />        echo </span><span style="color: #DD0000">'Foo: ' </span><span style="color: #007700">. </span><span style="color: #0000BB">$string </span><span style="color: #007700">. </span><span style="color: #0000BB">PHP_EOL</span><span style="color: #007700">;<br />    }<br />    <br />    public function </span><span style="color: #0000BB">printPHP</span><span style="color: #007700">()<br />    {<br />        echo </span><span style="color: #DD0000">'PHP is great.' </span><span style="color: #007700">. </span><span style="color: #0000BB">PHP_EOL</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">Bar </span><span style="color: #007700">extends </span><span style="color: #0000BB">Foo<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">printItem</span><span style="color: #007700">(</span><span style="color: #0000BB">$string</span><span style="color: #007700">)<br />    {<br />        echo </span><span style="color: #DD0000">'Bar: ' </span><span style="color: #007700">. </span><span style="color: #0000BB">$string </span><span style="color: #007700">. </span><span style="color: #0000BB">PHP_EOL</span><span style="color: #007700">;<br />    }<br />}<br /><br /></span><span style="color: #0000BB">$foo </span><span style="color: #007700">= new </span><span style="color: #0000BB">Foo</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$bar </span><span style="color: #007700">= new </span><span style="color: #0000BB">Bar</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$foo</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">printItem</span><span style="color: #007700">(</span><span style="color: #DD0000">'baz'</span><span style="color: #007700">); </span><span style="color: #FF8000">// 输出: 'Foo: baz'<br /></span><span style="color: #0000BB">$foo</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">printPHP</span><span style="color: #007700">();       </span><span style="color: #FF8000">// 输出: 'PHP is great' <br /></span><span style="color: #0000BB">$bar</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">printItem</span><span style="color: #007700">(</span><span style="color: #DD0000">'baz'</span><span style="color: #007700">); </span><span style="color: #FF8000">// 输出: 'Bar: baz'<br /></span><span style="color: #0000BB">$bar</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">printPHP</span><span style="color: #007700">();       </span><span style="color: #FF8000">// 输出: 'PHP is great'<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>

 </div>

 <div class="sect2" id="language.oop5.inheritance.internal-classes">
  <h3 class="title">返回类型与内部类兼容</h3>

  <p class="para">
   PHP 8.1 之前，大多数内部类或方法没有声明其返回类型，并且在继承它们时允许返回任何类型。
  </p>

  <p class="para">
   自 PHP 8.1.0 起，大多数内部方法开始“暂时”声明其返回类型，在这种情况下，方法的返回类型应该与继承的父级方法兼容；否则，将发出弃用通知。注意，没有指定返回声明也会视为签名不匹配，从而导致弃用通知。
  </p>

  <p class="para">
   如果由于 PHP 跨版本兼容性问题而无法为重写方法声明返回类型，则可以添加 <span class="classname"><a href="class.returntypewillchange.php" class="classname">ReturnTypeWillChange</a></span> 注解来消除弃用通知。
  </p>

  <div class="example" id="example-2">
   <p><strong>示例 #2 重写方法未声明任何返回类型</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">class </span><span style="color: #0000BB">MyDateTime </span><span style="color: #007700">extends </span><span style="color: #0000BB">DateTime<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">modify</span><span style="color: #007700">(</span><span style="color: #0000BB">string $modifier</span><span style="color: #007700">) { return </span><span style="color: #0000BB">false</span><span style="color: #007700">; }<br />}<br /><br /></span><span style="color: #FF8000">// "Deprecated: Return type of MyDateTime::modify(string $modifier) should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice" as of PHP 8.1.0<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>

  <div class="example" id="example-3">
   <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">class </span><span style="color: #0000BB">MyDateTime </span><span style="color: #007700">extends </span><span style="color: #0000BB">DateTime<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">modify</span><span style="color: #007700">(</span><span style="color: #0000BB">string $modifier</span><span style="color: #007700">): ?</span><span style="color: #0000BB">DateTime </span><span style="color: #007700">{ return </span><span style="color: #0000BB">null</span><span style="color: #007700">; }<br />}<br /><br /></span><span style="color: #FF8000">// "Deprecated: Return type of MyDateTime::modify(string $modifier): ?DateTime should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice" as of PHP 8.1.0<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>

  <div class="example" id="example-4">
   <p><strong>示例 #4 重写方法声明了错误的返回类型但没有弃用通知</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">class </span><span style="color: #0000BB">MyDateTime </span><span style="color: #007700">extends </span><span style="color: #0000BB">DateTime<br /></span><span style="color: #007700">{<br />    </span><span style="color: #FF8000">/**<br />     * @return DateTime|false<br />     */<br />    </span><span style="color: #007700">#[</span><span style="color: #0000BB">\ReturnTypeWillChange</span><span style="color: #007700">]<br />    public function </span><span style="color: #0000BB">modify</span><span style="color: #007700">(</span><span style="color: #0000BB">string $modifier</span><span style="color: #007700">) { return </span><span style="color: #0000BB">false</span><span style="color: #007700">; }<br />}<br /><br /></span><span style="color: #FF8000">// No notice is triggered<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>

 </div>

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