<?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 => 'fr',
  ),
  'this' => 
  array (
    0 => 'language.oop5.variance.php',
    1 => 'Covariance et Contravariance',
    2 => 'Covariance et Contravariance',
  ),
  'up' => 
  array (
    0 => 'language.oop5.php',
    1 => 'Les classes et les objets',
  ),
  'prev' => 
  array (
    0 => 'language.oop5.serialization.php',
    1 => 'S&eacute;rialisation d\'objets',
  ),
  'next' => 
  array (
    0 => 'language.oop5.lazy-objects.php',
    1 => 'Objets paresseux',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'fr',
    '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">Covariance et Contravariance</h2>

 <p class="para">
  En PHP 7.2.0, la contravariance partielle a été introduite en supprimant les restrictions de type
  sur les paramètres d&#039;une méthode enfant. À partir de PHP 7.4.0, la covariance et la contravariance complètes
  ont été ajoutées.
 </p>
 <p class="para">
  La covariance permet à une méthode enfant de retourner un type plus spécifique que le type de retour
  de sa méthode parente. La contravariance permet à un type de paramètre d&#039;être moins spécifique
  dans une méthode enfant que dans celui de la méthode parente.
 </p>
 <p class="para">
  Une déclaration de type est considérée comme plus spécifique dans le cas suivant :
  <ul class="itemizedlist">
   <li class="listitem">
    <span class="simpara">
     Un type est retiré d&#039;un
    <a href="language.types.type-system.php#language.types.type-system.composite.union" class="link">type union</a>
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     Un type est ajouté à un
    <a href="language.types.type-system.php#language.types.type-system.composite.intersection" class="link">type d&#039;intersection</a>
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     Un type de classe est transformé en un type de classe enfant
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
    <span class="type"><a href="language.types.iterable.php" class="type iterable">iterable</a></span> est remplacé par <span class="type"><a href="language.types.array.php" class="type array">array</a></span> ou <span class="classname"><a href="class.traversable.php" class="classname">Traversable</a></span>
    </span>
   </li>
  </ul>

  Un type de classe est considéré moins spécifique si l&#039;inverse est vrai.
 </p>

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

  <p class="para">
   Pour illustrer le fonctionnement de la covariance, une simple classe parente abstraite, <var class="varname">Animal</var>
   est créée. <var class="varname">Animal</var> sera étendu par des classes enfants,
  <var class="varname">Cat</var> et <var class="varname">Dog</var>.
  </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">Animal<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">speak</span><span style="color: #007700">();<br />}<br /><br />class </span><span style="color: #0000BB">Dog </span><span style="color: #007700">extends </span><span style="color: #0000BB">Animal<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">speak</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">" barks"</span><span style="color: #007700">;<br />    }<br />}<br /><br />class </span><span style="color: #0000BB">Cat </span><span style="color: #007700">extends </span><span style="color: #0000BB">Animal<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">speak</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">" meows"</span><span style="color: #007700">;<br />    }<br />}</span></span></code></div>
   </div>

  </div>

  <p class="para">
   Il est à noter qu&#039;il n&#039;y a pas de méthodes qui renvoient des valeurs dans cet exemple. Quelques fabriques
   seront ajoutées et renverront un nouvel objet de classe de type <var class="varname">Animal</var>,
  <var class="varname">Cat</var>, ou <var class="varname">Dog</var>.
  </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">AnimalShelter<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">adopt</span><span style="color: #007700">(</span><span style="color: #0000BB">string $name</span><span style="color: #007700">): </span><span style="color: #0000BB">Animal</span><span style="color: #007700">;<br />}<br /><br />class </span><span style="color: #0000BB">CatShelter </span><span style="color: #007700">implements </span><span style="color: #0000BB">AnimalShelter<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">adopt</span><span style="color: #007700">(</span><span style="color: #0000BB">string $name</span><span style="color: #007700">): </span><span style="color: #0000BB">Cat </span><span style="color: #FF8000">// au lieu de retourner le type de classe Animal, on peut retourner le type de classe Cat<br />    </span><span style="color: #007700">{<br />        return new </span><span style="color: #0000BB">Cat</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">DogShelter </span><span style="color: #007700">implements </span><span style="color: #0000BB">AnimalShelter<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">adopt</span><span style="color: #007700">(</span><span style="color: #0000BB">string $name</span><span style="color: #007700">): </span><span style="color: #0000BB">Dog </span><span style="color: #FF8000">// au lieu de retourner le type de classe Animal, on peut retourner le type de classe Dog<br />    </span><span style="color: #007700">{<br />        return new </span><span style="color: #0000BB">Dog</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">$kitty </span><span style="color: #007700">= (new </span><span style="color: #0000BB">CatShelter</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">adopt</span><span style="color: #007700">(</span><span style="color: #DD0000">"Ricky"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$kitty</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">speak</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">$doggy </span><span style="color: #007700">= (new </span><span style="color: #0000BB">DogShelter</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">adopt</span><span style="color: #007700">(</span><span style="color: #DD0000">"Mavrick"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$doggy</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">speak</span><span style="color: #007700">();</span></span></code></div>
   </div>

   <p class="para">L&#039;exemple ci-dessus va afficher :</p>
   <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Ricky meows
Mavrick barks
</pre></div>
   </div>
  </div>
 </div>

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

  <p class="para">
   En reprenant l&#039;exemple précédent avec les classes <var class="varname">Animal</var>,
   <var class="varname">Cat</var> et <var class="varname">Dog</var>, une classe appelée
   <var class="varname">Food</var> et <var class="varname">AnimalFood</var> seront incluses, et
   une méthode <var class="varname">eat(AnimalFood $food)</var> est ajoutée à la classe abstraite
   <var class="varname">Animal</var> .
  </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">Food </span><span style="color: #007700">{}<br /><br />class </span><span style="color: #0000BB">AnimalFood </span><span style="color: #007700">extends </span><span style="color: #0000BB">Food </span><span style="color: #007700">{}<br /><br />abstract class </span><span style="color: #0000BB">Animal<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">eat</span><span style="color: #007700">(</span><span style="color: #0000BB">AnimalFood $food</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">" eats " </span><span style="color: #007700">. </span><span style="color: #0000BB">get_class</span><span style="color: #007700">(</span><span style="color: #0000BB">$food</span><span style="color: #007700">);<br />    }<br />}</span></span></code></div>
   </div>

  </div>

  <p class="para">
   Afin de voir le comportement de la contravariance, la
   méthode <var class="varname">eat</var> est surchargée dans la classe <var class="varname">Dog</var> afin d&#039;autoriser
   n&#039;importe quel objet de type <var class="varname">Food</var>. La classe <var class="varname">Cat</var> reste inchangée.
  </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">Dog </span><span style="color: #007700">extends </span><span style="color: #0000BB">Animal<br /></span><span style="color: #007700">{<br />    public function </span><span style="color: #0000BB">eat</span><span style="color: #007700">(</span><span style="color: #0000BB">Food $food</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">" eats " </span><span style="color: #007700">. </span><span style="color: #0000BB">get_class</span><span style="color: #007700">(</span><span style="color: #0000BB">$food</span><span style="color: #007700">);<br />    }<br />}</span></span></code></div>
   </div>

  </div>

  <p class="para">
   L&#039;exemple suivant montre le comportement de la contravariance.
  </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 />$kitty </span><span style="color: #007700">= (new </span><span style="color: #0000BB">CatShelter</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">adopt</span><span style="color: #007700">(</span><span style="color: #DD0000">"Ricky"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$catFood </span><span style="color: #007700">= new </span><span style="color: #0000BB">AnimalFood</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$kitty</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">eat</span><span style="color: #007700">(</span><span style="color: #0000BB">$catFood</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">$doggy </span><span style="color: #007700">= (new </span><span style="color: #0000BB">DogShelter</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">adopt</span><span style="color: #007700">(</span><span style="color: #DD0000">"Mavrick"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$banana </span><span style="color: #007700">= new </span><span style="color: #0000BB">Food</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$doggy</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">eat</span><span style="color: #007700">(</span><span style="color: #0000BB">$banana</span><span style="color: #007700">);</span></span></code></div>
   </div>

   <p class="para">L&#039;exemple ci-dessus va afficher :</p>
   <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Ricky eats AnimalFood
Mavrick eats Food
</pre></div>
   </div>

  <p class="para">
   Mais que se passe-t-il si <var class="varname">$kitty</var> essaie de manger (<span class="methodname"><strong>eat()</strong></span>) la
   banane (<var class="varname">$banana</var>) ?
  </p>

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

   <p class="para">L&#039;exemple ci-dessus va afficher :</p>
   <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Fatal error: Uncaught TypeError: Argument 1 passed to Animal::eat() must be an instance of AnimalFood, instance of Food given
</pre></div>
   </div>
  </div>
 </div>
 <div class="sect2">
  <h3 class="title">Variation de type des propriétés</h3>
  <p class="simpara">
   Par défaut, les propriétés ne sont ni covariantes ni contravariantes, donc invariantes.
   Autrement dit, leur type ne peut pas du tout changer dans une classe enfant.
   La raison en est que les opérations &quot;get&quot; doivent être covariantes,
   et les opérations &quot;set&quot; doivent être contravariantes.
   La seule façon pour une propriété de satisfaire ces deux exigences est d&#039;être invariante.
  </p>
  <p class="simpara">
   À partir de PHP 8.4.0, avec l&#039;ajout des propriétés abstraites (sur une interface ou une classe abstraite) et
   <a href="language.oop5.property-hooks.php#language.oop5.property-hooks.virtual" class="link">propriétés virtuelles</a>,
   il est possible de déclarer une propriété qui n&#039;a qu&#039;une opération &quot;get&quot; ou &quot;set&quot;.
   En conséquence, les propriétés abstraites ou les propriétés virtuelles qui n&#039;ont que l&#039;opération &quot;get&quot; requise peuvent être covariantes.
   De même, une propriété abstraite ou une propriété virtuelle qui n&#039;a que l&#039;opération &quot;set&quot; requise peut être contravariante.
  </p>
  <p class="simpara">
   Cependant, une fois qu&#039;une propriété a à la fois une opération &quot;get&quot; et &quot;set&quot;,
   elle n&#039;est plus covariante ni contravariante pour une extension future.
   Autrement dit, elle devient désormais invariante.
  </p>
  <div class="example" id="example-1">
   <p><strong>Exemple #1 Variation du type des propriétés</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">// Seule l'opération "get" est requise, donc cela peut être covariant.<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">// Cela peut être un type plus restrictif, car le côté "get"<br />    // retourne toujours un Animal. Cependant, en tant que propriété native,<br />    // les enfants de cette classe ne peuvent plus changer le type.<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">// Ceci N'EST PAS AUTORISÉ, car DogOwner::$pet a à la fois<br />    // les opérations "get" et "set" définies et requises.<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); ?>