<?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 => 'de',
  ),
  'this' => 
  array (
    0 => 'language.oop5.variance.php',
    1 => 'Kovarianz und Kontravarianz',
    2 => 'Kovarianz und Kontravarianz',
  ),
  'up' => 
  array (
    0 => 'language.oop5.php',
    1 => 'Klassen und Objekte',
  ),
  'prev' => 
  array (
    0 => 'language.oop5.serialization.php',
    1 => 'Serialisierung von Objekten',
  ),
  'next' => 
  array (
    0 => 'language.oop5.lazy-objects.php',
    1 => 'Lazy Objects',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'de',
    'path' => 'language/oop5/variance.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="language.oop5.variance" class="sect1">
 <h2 class="title">Kovarianz und Kontravarianz</h2>

 <p class="para">
  Mit PHP 7.2.0 wurde teilweise Kontravarianz eingeführt, indem
  Typeneinschränkungen bei Parametern von Kindmethoden entfernt wurden.
  Mit PHP 7.4.0 wurde dann vollständige Unterstützung für Kovarianz und
  Kontravarianz eingeführt.
 </p>
 <p class="para">
  Kovarianz erlaubt es den Methoden eines Kindes, einen spezifischeren Typen
  als die Elternmethode für den Rückgabewert zurückzugeben.
  Die Kontravarianz erlaubt einen weniger spezifischen Parametertyp in einer
  Kindmethode als in der Elternmethode.
 </p>
 <p class="para">
  Eine Typdeklaration wird in den folgenden Fällen als spezifischer angesehen:
  <ul class="itemizedlist">
   <li class="listitem">
    <span class="simpara">
     Ein Typ wird aus einem <a href="language.types.type-system.php#language.types.type-system.composite.union" class="link">Vereinigungstypen</a> entfernt
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     Ein Typ wird zu einem
     <a href="language.types.type-system.php#language.types.type-system.composite.intersection" class="link">Schnittmengentypen</a>
     hinzugefügt.
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     Ein Klassentyp wird zu dem Typen eines seiner Kinder geändert
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     <span class="type"><a href="language.types.iterable.php" class="type iterable">iterable</a></span> wird zu <span class="type"><a href="language.types.array.php" class="type array">array</a></span> oder <span class="classname"><a href="class.traversable.php" class="classname">Traversable</a></span> geändert
    </span>
   </li>
  </ul>

  Falls das Gegenteil zutrifft, wird ein Klassentyp als weniger
  spezifisch angesehen.
 </p>

 <div class="sect2" id="language.oop5.variance.covariance">
  <h3 class="title">Kovarianz</h3>

  <p class="para">
   Um Kovarianz zu illustrieren, wird eine einfache abstrakte Elternklasse
   <var class="varname">Tier</var> erzeugt. <var class="varname">Tier</var> wird von seinen
   Kindern <var class="varname">Katze</var> und <var class="varname">Hund</var> beerbt.
  </p>

  <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">abstract class </span><span style="color: #0000BB">Tier<br /></span><span style="color: #007700">{<br />    protected </span><span style="color: #0000BB">string $name</span><span style="color: #007700">;<br /><br />    public function </span><span style="color: #0000BB">__construct</span><span style="color: #007700">(</span><span style="color: #0000BB">string $name</span><span style="color: #007700">)<br />    {<br />        </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">name </span><span style="color: #007700">= </span><span style="color: #0000BB">$name</span><span style="color: #007700">;<br />    }<br /><br />    abstract public function </span><span style="color: #0000BB">gibLaut</span><span style="color: #007700">();<br />}<br /><br />class </span><span style="color: #0000BB">Hund </span><span style="color: #007700">extends </span><span style="color: #0000BB">Tier<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">gibLaut</span><span style="color: #007700">()<br />    {<br />        echo </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">name </span><span style="color: #007700">. </span><span style="color: #DD0000">" bellt"</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">Katze </span><span style="color: #007700">extends </span><span style="color: #0000BB">Tier<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">gibLaut</span><span style="color: #007700">()<br />    {<br />        echo </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">name </span><span style="color: #007700">. </span><span style="color: #DD0000">" miaut"</span><span style="color: #007700">;<br />    }<br />}</span></span></code></div>
   </div>

  </div>

  <p class="para">
   Beachtenswert ist, dass keine der Methoden hier einen Wert zurückgibt. Es werden nun
   ein paar Factories hinzugefügt, die ein neues Objekt der Klassen <var class="varname">Tier</var>,
   <var class="varname">Katze</var> oder <var class="varname">Hund</var> erzeugen.
  </p>

  <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">interface </span><span style="color: #0000BB">TierHeim<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">adoptiere</span><span style="color: #007700">(</span><span style="color: #0000BB">string $name</span><span style="color: #007700">): </span><span style="color: #0000BB">Tier</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">KatzenHeim </span><span style="color: #007700">implements </span><span style="color: #0000BB">TierHeim<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">adoptiere</span><span style="color: #007700">(</span><span style="color: #0000BB">string $name</span><span style="color: #007700">): </span><span style="color: #0000BB">Katze </span><span style="color: #FF8000">// statt den Klassentyp Tier zurückzugeben, kann hier Typ Katze verwendet werden<br />    </span><span style="color: #007700">{<br />        return new </span><span style="color: #0000BB">Katze</span><span style="color: #007700">(</span><span style="color: #0000BB">$name</span><span style="color: #007700">);<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">HundeHeim </span><span style="color: #007700">implements </span><span style="color: #0000BB">TierHeim<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">adoptiere</span><span style="color: #007700">(</span><span style="color: #0000BB">string $name</span><span style="color: #007700">): </span><span style="color: #0000BB">Hund </span><span style="color: #FF8000">// statt den Klassentyp Tier zurückzugeben, kann hier Typ Hund verwendet werden<br />    </span><span style="color: #007700">{<br />        return new </span><span style="color: #0000BB">Hund</span><span style="color: #007700">(</span><span style="color: #0000BB">$name</span><span style="color: #007700">);<br />    }<br />}<br /><br /></span><span style="color: #0000BB">$kaetzchen </span><span style="color: #007700">= (new </span><span style="color: #0000BB">KatzenHeim</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">adoptiere</span><span style="color: #007700">(</span><span style="color: #DD0000">"Ricky"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$kaetzchen</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">gibLaut</span><span style="color: #007700">();<br />echo </span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">$huendchen </span><span style="color: #007700">= (new </span><span style="color: #0000BB">HundeHeim</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">adoptiere</span><span style="color: #007700">(</span><span style="color: #DD0000">"Mavrick"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$huendchen</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">gibLaut</span><span style="color: #007700">();</span></span></code></div>
   </div>

   <p class="para">Das oben gezeigte Beispiel erzeugt folgende Ausgabe:</p>
   <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Ricky miaut
Mavrick bellt
</pre></div>
   </div>
  </div>
 </div>

 <div class="sect2" id="language.oop5.variance.contravariance">
  <h3 class="title">Kontravarianz</h3>

  <p class="para">
   Um das vorherige Beispiel mit den Klassen <var class="varname">Tier</var>,
   <var class="varname">Katze</var> und <var class="varname">Hund</var> fortzusetzen,
   werden nun die Klassen <var class="varname">Nahrung</var> sowie <var class="varname">Tierfutter</var>
   definiert, sowie auch eine Methode <var class="varname">iss(Tierfutter $futter)</var> zur
   abstrakten Klasse <var class="varname">Tier</var> hinzugefügt.
  </p>

  <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">Nahrung </span><span style="color: #007700">{}<br /><br />class </span><span style="color: #0000BB">Tierfutter </span><span style="color: #007700">extends </span><span style="color: #0000BB">Nahrung </span><span style="color: #007700">{}<br /><br />abstract class </span><span style="color: #0000BB">Tier<br /></span><span style="color: #007700">{<br />    protected </span><span style="color: #0000BB">string $name</span><span style="color: #007700">;<br /><br />    public function </span><span style="color: #0000BB">__construct</span><span style="color: #007700">(</span><span style="color: #0000BB">string $name</span><span style="color: #007700">)<br />    {<br />        </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">name </span><span style="color: #007700">= </span><span style="color: #0000BB">$name</span><span style="color: #007700">;<br />    }<br /><br />    public function </span><span style="color: #0000BB">iss</span><span style="color: #007700">(</span><span style="color: #0000BB">Tierfutter $futter</span><span style="color: #007700">)<br />    {<br />        echo </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">name </span><span style="color: #007700">. </span><span style="color: #DD0000">" isst " </span><span style="color: #007700">. </span><span style="color: #0000BB">get_class</span><span style="color: #007700">(</span><span style="color: #0000BB">$futter</span><span style="color: #007700">);<br />    }<br />}</span></span></code></div>
   </div>

  </div>

  <p class="para">
   Um das Verhalten der Kontravarianz zu sehen, wird nun die Methode
   <var class="varname">iss</var> in der Klasse <var class="varname">Hund</var> überschrieben,
   um jedes Objekt der Klasse <var class="varname">Nahrung</var> zuzulassen. Die Klasse
   <var class="varname">Katze</var> bleibt unverändert.
  </p>

  <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">Hund </span><span style="color: #007700">extends </span><span style="color: #0000BB">Tier<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">iss</span><span style="color: #007700">(</span><span style="color: #0000BB">Nahrung $futter</span><span style="color: #007700">) {<br />        echo </span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">name </span><span style="color: #007700">. </span><span style="color: #DD0000">" isst " </span><span style="color: #007700">. </span><span style="color: #0000BB">get_class</span><span style="color: #007700">(</span><span style="color: #0000BB">$futter</span><span style="color: #007700">);<br />    }<br />}</span></span></code></div>
   </div>

  </div>

  <p class="para">
   Das folgende Beispiel zeigt das Verhalten der Kontravarianz.
  </p>

  <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 />$kaetzchen </span><span style="color: #007700">= (new </span><span style="color: #0000BB">KatzenHeim</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">adoptiere</span><span style="color: #007700">(</span><span style="color: #DD0000">"Ricky"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$katzenFutter </span><span style="color: #007700">= new </span><span style="color: #0000BB">Tierfutter</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$kaetzchen</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">iss</span><span style="color: #007700">(</span><span style="color: #0000BB">$katzenFutter</span><span style="color: #007700">);<br />echo </span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">$huendchen </span><span style="color: #007700">= (new </span><span style="color: #0000BB">HundeHeim</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">adoptiere</span><span style="color: #007700">(</span><span style="color: #DD0000">"Mavrick"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$banane </span><span style="color: #007700">= new </span><span style="color: #0000BB">Nahrung</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$huendchen</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">iss</span><span style="color: #007700">(</span><span style="color: #0000BB">$banane</span><span style="color: #007700">);</span></span></code></div>
   </div>

   <p class="para">Das oben gezeigte Beispiel erzeugt folgende Ausgabe:</p>
   <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Ricky isst Tierfutter
Mavrick isst Nahrung
</pre></div>
   </div>

   <p class="para">
    Was geschieht nun aber, wenn man der <span class="methodname"><strong>iss()</strong></span>-Methode
    von <var class="varname">$kaetzchen</var> versucht die <var class="varname">$banane</var>
    zu übergeben?
   </p>

   <div class="example-contents">
<div class="annotation-interactive phpcode"><code><span style="color: #000000">$kitty-&gt;iss($banane);</span></code></div>
   </div>

   <p class="para">Das oben gezeigte Beispiel erzeugt folgende Ausgabe:</p>
   <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Fatal error: Uncaught TypeError: Argument 1 passed to Tier::iss() must be an instance of Tierfutter, instance of Nahrung given
</pre></div>
   </div>
  </div>
 </div>
 <div class="sect2">
  <h3 class="title">Varianz der Eigenschaften</h3>
  <p class="simpara">
   Standardmäßig sind Eigenschaften weder kovariant noch kontravariant, d. h.
   sie sind invariant.
   Das bedeutet, dass sich ihr Typ in einer Kindklasse überhaupt nicht ändern
   darf.
   Der Grund dafür ist, dass &quot;get&quot;-Operationen kovariant und &quot;set&quot;-Operationen
   kontravariant sein müssen.
   Die einzige Möglichkeit für eine Eigenschaft, beide Anforderungen zu
   erfüllen, besteht darin, invariant zu sein.
  </p>
  <p class="simpara">
   Seit PHP 8.4.0 ist es mit der Einführung von abstrakten Eigenschaften (auf
   einer Schnittstelle oder einer abstrakten Klasse) und
   <a href="language.oop5.property-hooks.php#language.oop5.property-hooks.virtual" class="link">virtuellen Eigenschaften</a>
   möglich, eine Eigenschaft zu deklarieren, die nur eine get- oder
   set-Operation hat.
   Folglich können abstrakte Eigenschaften oder virtuelle Eigenschaften, die
   nur eine &quot;get&quot;-Operation benötigen, kovariant sein.
   Ebenso kann eine abstrakte Eigenschaft oder eine virtuelle Eigenschaft, die
   nur eine &quot;set&quot;-Operation benötigt, kontravariant sein.
  </p>
  <p class="simpara">
   Sobald eine Eigenschaft jedoch sowohl eine get- als auch eine set-Operation
   hat, ist sie für weitere Erweiterungen nicht mehr kovariant oder
   kontravariant.
   Mit anderen Worten: Sie ist nun invariant.
  </p>
  <div class="example" id="example-1">
   <p><strong>Beispiel #1 Varianz des Eigenschaftstyps</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">Animal </span><span style="color: #007700">{}<br />class </span><span style="color: #0000BB">Dog </span><span style="color: #007700">extends </span><span style="color: #0000BB">Animal </span><span style="color: #007700">{}<br />class </span><span style="color: #0000BB">Poodle </span><span style="color: #007700">extends </span><span style="color: #0000BB">Dog </span><span style="color: #007700">{}<br /><br />interface </span><span style="color: #0000BB">PetOwner<br /></span><span style="color: #007700">{<br />    </span><span style="color: #FF8000">// Es wird nur eine get-Operation benötigt, so dass diese kovariant<br />    // sein kann.<br />    </span><span style="color: #007700">public </span><span style="color: #0000BB">Animal $pet </span><span style="color: #007700">{ </span><span style="color: #0000BB">get</span><span style="color: #007700">; }<br />}<br /><br />class </span><span style="color: #0000BB">DogOwner </span><span style="color: #007700">implements </span><span style="color: #0000BB">PetOwner<br /></span><span style="color: #007700">{<br />    </span><span style="color: #FF8000">// Dies kann ein restriktiverer Typ sein, da die "get"-Seite immer ein<br />    // Animal zurückgibt. Da es sich jedoch um eine native Eigenschaft handelt,<br />    // können Kinder dieser Klasse den Typ nicht mehr ändern.<br />    </span><span style="color: #007700">public </span><span style="color: #0000BB">Dog $pet</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">PoodleOwner </span><span style="color: #007700">extends </span><span style="color: #0000BB">DogOwner<br /></span><span style="color: #007700">{<br />    </span><span style="color: #FF8000">// Dies ist NICHT ZULÄSSIG, da für DogOwner::$pet sowohl get- als auch<br />    // set-Operationen definiert sind und benötigt werden.<br />    </span><span style="color: #007700">public </span><span style="color: #0000BB">Poodle $pet</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

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