svn: /phpdoc/ru/trunk/language/oop5/ variance.xml

[email protected] (Andrey Gromov)
Newsgroups php.doc.ru
Message-ID <[email protected]>
rjhdby                                   Mon, 06 Jan 2020 11:40:33 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=348807

Log:
new

Changed paths:
    A   phpdoc/ru/trunk/language/oop5/variance.xml
svn-diffs-348807.txt (text/x-diff, 8 KB)
Added: phpdoc/ru/trunk/language/oop5/variance.xml
===================================================================
--- phpdoc/ru/trunk/language/oop5/variance.xml	                        (rev 0)
+++ phpdoc/ru/trunk/language/oop5/variance.xml	2020-01-06 11:40:33 UTC (rev 348807)
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- $Revision$ -->
+<!-- EN-Revision: 348562 Maintainer: rjhdby Status: ready -->
+<!-- Reviewed: no -->
+<sect1 xml:id="language.oop5.variance" xmlns="http://docbook.org/ns/docbook">
+ <title>Ковариантность и Контравариантность</title>
+
+ <para>
+  До версии 7.4.0, в PHP, типы параметров и возвращаемых значений,
+  по большей части были инвариантны. Это значит, что если метод
+  родительского класса принимал параметром или возвращал значение
+  типа <varname>T</varname>, то и в дочернем классе соответствующий
+  параметр или возвращаемое значение <emphasis>обязаны</emphasis>
+  быть того же типа <varname>T</varname>.
+ </para>
+
+ <para>
+  Начиная с PHP 7.4.0 появилась поддержка ковариантности и
+  контравариантности. Звучит страшно, но на самом деле всё просто и
+  очень полезно в объектно ориентированном подходе.
+ </para>
+
+ <sect2 xml:id="language.oop5.variance.covariance">
+  <title>Ковариантность</title>
+
+  <para>
+   Ковариантность позволяет дочернему методу возвращать более
+   конкретный подтип типа, возвращаемого родительским методом.
+   Проще всего показать на примере.
+  </para>
+
+  <para>
+   Возьмём простой абстрактный родительский класс
+   <varname>Animal</varname> и создадим на его основе два дочерних
+   класса <varname>Cat</varname> и <varname>Dog</varname>.
+  </para>
+
+  <informalexample>
+   <programlisting role="php">
+<![CDATA[
+<?php
+
+abstract class Animal
+{
+    protected string $name;
+
+    public function __construct(string $name)
+    {
+        $this->name = $name;
+    }
+
+    abstract public function speak();
+}
+
+class Dog extends Animal
+{
+    public function speak()
+    {
+        echo $this->name . " лает";
+    }
+}
+
+class Cat extends Animal
+{
+    public function speak()
+    {
+        echo $this->name . " мяукает";
+    }
+}
+]]>
+   </programlisting>
+  </informalexample>
+
+  <para>
+   Обратите внимание, что в примере отсутствуют методы возвращающие
+   какие либо значения. В следующем примере мы создадим несколько
+   фабрик, возвращающих объекты типов
+   <varname>Animal</varname>, <varname>Cat</varname> и
+   <varname>Dog</varname>.
+   Именно на этом примере мы продемонстрируем ковариантность.
+  </para>
+
+  <informalexample>
+   <programlisting role="php">
+<![CDATA[
+<?php
+
+interface AnimalShelter
+{
+    public function adopt(string $name): Animal;
+}
+
+class CatShelter implements AnimalShelter
+{
+    public function adopt(string $name): Cat // Возвращаем класс Cat вместо  Animal
+    {
+        return new Cat($name);
+    }
+}
+
+class DogShelter implements AnimalShelter
+{
+    public function adopt(string $name): Dog // Возвращаем класс Dog вместо  Animal
+    {
+        return new Dog($name);
+    }
+}
+
+$kitty = (new CatShelter)->adopt("Рыжик");
+$kitty->speak();
+echo "\n";
+
+$doggy = (new DogShelter)->adopt("Бобик");
+$doggy->speak();
+]]>
+   </programlisting>
+   &example.outputs;
+   <screen>
+<![CDATA[
+Рыжик мяукает
+Бобик лает
+]]>
+   </screen>
+  </informalexample>
+ </sect2>
+
+ <sect2 xml:id="language.oop5.variance.contravariance">
+  <title>Контравариантность</title>
+
+  <para>
+   С другой стороны, контравариантность позволяет дочернему методу
+   принимать параметром менее конкретный тип, чем задано в
+   родительском. В продолжение предыдущего примера, где мы
+   использовали классы <varname>Animal</varname>,
+   <varname>Cat</varname> и <varname>Dog</varname>, мы
+   введем новые классы <varname>Food</varname> и <varname>AnimalFood</varname> и добавим в абстрактный класс
+   <varname>Animal</varname> новый метод
+   <varname>eat(AnimalFood $food)</varname>.
+  </para>
+
+  <informalexample>
+   <programlisting role="php">
+<![CDATA[
+<?php
+
+class Food {}
+
+class AnimalFood extends Food {}
+
+abstract class Animal
+{
+    protected string $name;
+
+    public function __construct(string $name)
+    {
+        $this->name = $name;
+    }
+
+    public function eat(AnimalFood $food)
+    {
+        echo $this->name . " хомячит " . get_class($food);
+    }
+}
+]]>
+   </programlisting>
+  </informalexample>
+
+  <para>
+   Чтобы увидеть суть контравариантности, мы переопределим метод
+   <varname>eat</varname> класса <varname>Dog</varname> таким
+   образом, чтобы он мог принимать любой объект класса
+   <varname>Food</varname>. Класс <varname>Cat</varname> оставим
+   без изменений.
+  </para>
+
+  <informalexample>
+   <programlisting role="php">
+<![CDATA[
+<?php
+
+class Dog extends Animal
+{
+    public function eat(Food $food) {
+        echo $this->name . " хомячит " . get_class($food);
+    }
+}
+]]>
+   </programlisting>
+  </informalexample>
+
+  <para>
+   Теперь мы можем увидеть, как работает контравариантность.
+  </para>
+
+  <informalexample>
+   <programlisting role="php">
+<![CDATA[
+<?php
+
+$kitty = (new CatShelter)->adopt("Рыжик");
+$catFood = new AnimalFood();
+$kitty->eat($catFood);
+echo "\n";
+
+$doggy = (new DogShelter)->adopt("Бобик");
+$banana = new Food();
+$doggy->eat($banana);
+]]>
+   </programlisting>
+   &example.outputs;
+   <screen>
+<![CDATA[
+Рыжик хомячит AnimalFood
+Бобик хомячит Food
+]]>
+   </screen>
+
+   <para>
+    Но что случится, если <varname>$kitty</varname> попробует
+    съесть (<varname>eat</varname>) банан
+    (<varname>$banana</varname>)?
+   </para>
+
+   <programlisting role="php">
+<![CDATA[
+$kitty->eat($banana);
+]]>
+   </programlisting>
+   &example.outputs;
+   <screen>
+<![CDATA[
+Fatal error: Uncaught TypeError: Argument 1 passed to Animal::eat() must be an instance of AnimalFood, instance of Food given
+]]>
+   </screen>
+  </informalexample>
+ </sect2>
+</sect1>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+indent-tabs-mode:nil
+sgml-parent-document:nil
+sgml-default-dtd-file:"~/.phpdoc/manual.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+vim600: syn=xml fen fdm=syntax fdl=2 si
+vim: et tw=78 syn=sgml
+vi: ts=1 sw=1
+-->


Property changes on: phpdoc/ru/trunk/language/oop5/variance.xml
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
\ No newline at end of property
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.