<?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 => 'pt_BR',
  ),
  'this' => 
  array (
    0 => 'language.oop5.variance.php',
    1 => 'Covari&acirc;ncia e Contravari&acirc;ncia',
    2 => 'Covari&acirc;ncia e Contravari&acirc;ncia',
  ),
  'up' => 
  array (
    0 => 'language.oop5.php',
    1 => 'Classes e Objetos',
  ),
  'prev' => 
  array (
    0 => 'language.oop5.serialization.php',
    1 => 'Serializa&ccedil;&atilde;o de Objetos',
  ),
  'next' => 
  array (
    0 => 'language.oop5.lazy-objects.php',
    1 => 'Objetos Lentos',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'pt_BR',
    '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">Covariância e Contravariância</h2>

 <p class="para">
  No 7.2.0, a contravariância parcial foi introduzida removendo as restrições de tipo
  nos parâmetros em um método filho. A partir do PHP 7.4.0, foi adicionado suporte
  a covariância e contravariância completas.
 </p>
 <p class="para">
  A covariância permite que um método de uma classe filha retorne um tipo mais específico que o tipo de retorno
  do método da classe pai. A contravariância permite a um tipo de parâmetro ser menos
  específico em um método de classe filha, em relação à classe pai.
 </p>
 <p class="para">
  Uma declaração de tipo é considerada mais específica nos seguintes casos:
  <ul class="itemizedlist">
   <li class="listitem">
    <span class="simpara">
     Um tipo é removido de um
     <a href="language.types.type-system.php#language.types.type-system.composite.union" class="link">tipo união</a>
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     Um tipo é adicionado a um
     <a href="language.types.type-system.php#language.types.type-system.composite.intersection" class="link">tipo interseção</a>
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     Um tipo de classe é alterado para um tipo de classe filha
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     <span class="type"><a href="language.types.iterable.php" class="type iterable">iterable</a></span> é alterado para <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>

  Uma classe de tipo é considerada menos específica se o oposto for verdadeiro.
 </p>

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

  <p class="para">
   Para ilustrar como uma variância funciona, uma classe pai abstrata simples, <var class="varname">Animal</var>
   é criada. <var class="varname">Animal</var> será estendida por classes filhas,
   <var class="varname">Cat</var> e <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">
   Observe que não há nenhum método que retorne valores neste exemplo. Serão adicionados
   alguns métodos que retornam um novo objeto do tipo de classe <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">// em vez de retornar o tipo Animal, pode retornar o tipo 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">// em vez de retornar o tipo Animal, pode retornar o tipo 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">O exemplo acima produzirá:</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">Contravariância</h3>

  <p class="para">
   Continuando com o exemplo anterior com as classes <var class="varname">Animal</var>,
   <var class="varname">Cat</var> e <var class="varname">Dog</var>, duas classes chamadas
   <var class="varname">Food</var> e <var class="varname">AnimalFood</var> serão incluídas, e
   um método <var class="varname">eat(AnimalFood $food)</var> é adicionado à classe abstrata
   <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">
   Para ver o comportamento da contravariância, o método
   <var class="varname">eat</var> é substituído na classe <var class="varname">Dog</var> para permitir
   qualquer objeto do tipo <var class="varname">Food</var>. A classe <var class="varname">Cat</var> permanece inalterada.
  </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">
   O próximo exemplo irá mostrar o comportamento da contravariância.
  </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">O exemplo acima produzirá:</p>
   <div class="example-contents screen">
<div class="annotation-interactive cdata"><pre>
Ricky eats AnimalFood
Mavrick eats Food
</pre></div>
   </div>

   <p class="para">
    Mas o que acontece se <var class="varname">$kitty</var> tentar comer (<span class="methodname"><strong>eat()</strong></span>) a
    <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">O exemplo acima produzirá:</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">Variância de propriedade</h3>
  <p class="simpara">
   Por padrão, as propriedades não são covariantes nem contravariantes e, portanto, invariantes.
   Ou seja, o tipo delas não pode mudar em nenhuma classe filha.
   A razão para isso é que as operações &quot;get&quot; devem ser covariantes
   e as operações &quot;set&quot; devem ser contravariantes.
   A única maneira de uma propriedade satisfazer ambos os requisitos é ser invariante.
  </p>
  <p class="simpara">
   A partir do PHP 8.4.0, com a adição de propriedades abstratas (em uma interface ou classe abstrata) e
   <a href="language.oop5.property-hooks.php#language.oop5.property-hooks.virtual" class="link">propriedades virtuais</a>,
   é possível declarar uma propriedade que possui apenas uma operação get ou set.
   Como resultado, propriedades abstratas ou propriedades virtuais que exigem apenas uma operação &quot;get&quot; podem ser covariantes.
   Da mesma forma, uma propriedade abstrata ou propriedade virtual que requerem apenas uma operação &quot;set&quot; pode ser contravariante.
  </p>
  <p class="simpara">
   Uma vez que uma propriedade tenha uma operação get e set, entretanto,
   ela não será mais covariante ou contravariante para extensão adicional.
   Ou seja, agora é invariante.
  </p>
  <div class="example" id="example-1">
   <p><strong>Exemplo #1 Variância do tipo de propriedade</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">// Apenas uma operação get é necessária, portanto isso pode ser covariante.<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">// Este pode ser um tipo mais restritivo, já que o lado "get"<br />    // ainda retorna um Animal.  Porém, como propriedade nativa,<br />    // os filhos desta classe não podem mais alterar o tipo.<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">// Isso NÃO É PERMITIDO, porque DogOwner::$pet tem operações<br />    // get e set definidas e obrigatórias.<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); ?>