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