1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-24 07:42:22 +01:00
Files
archived-doc-ru/language/types/declarations.xml
2025-10-13 00:45:41 +03:00

844 lines
26 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 0ece873cecfc4dacd14e8bebbec12c6e00de56a0 Maintainer: rjhdby Status: ready -->
<!-- Reviewed: no -->
<sect1 xml:id="language.types.declarations">
<title>Объявления типов</title>
<para>
Объявления типов добавляют параметрам функций, значениям возврата,
начиная с PHP 7.4.0 свойствам класса и начиная с PHP 8.3.0 константам класса.
Объявления типов гарантируют, что при вызове значение принадлежит заданному типу,
иначе PHP выбросит ошибку <classname>TypeError</classname>.
</para>
<para>
Каждый тип, который поддерживает PHP, за исключением ресурсов (<type>resource</type>),
разрешается указывать в пользовательском объявлении типа.
Страница содержит журнал изменений доступности отдельных типов
и документацию, которая описывает правила объявления типов.
</para>
<note>
<para>
Класс, который реализует метод интерфейса или переопределяет метод
родительского класса,
подчиняется правилам совместимости.
Метод совместим, если следует
<link linkend="language.oop5.variance">правилам вариантности</link>.
</para>
</note>
<sect2 role="changelog">
&reftitle.changelog;
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>&Version;</entry>
<entry>&Description;</entry>
</row>
</thead>
<tbody>
<row>
<entry>8.3.0</entry>
<entry>
Добавили поддержку типизации констант классов, интерфейсов, трейтов и перечислений.
</entry>
</row>
<row>
<entry>8.2.0</entry>
<entry>
Добавили поддержку <acronym>DNF</acronym>-типов.
</entry>
</row>
<row>
<entry>8.2.0</entry>
<entry>
Добавили поддержку самостоятельного типа <type>true</type>.
</entry>
</row>
<row>
<entry>8.2.0</entry>
<entry>
Типы <type>null</type> и <type>false</type> разрешили указывать отдельно.
</entry>
</row>
<row>
<entry>8.1.0</entry>
<entry>
Добавили поддержку пересечений типов.
</entry>
</row>
<row>
<entry>8.1.0</entry>
<entry>
Возврат по ссылке из функции с типом значения возврата <type>void</type> устарел.
</entry>
</row>
<row>
<entry>8.1.0</entry>
<entry>
Для значения возврата добавили поддержку типа <type>never</type>.
</entry>
</row>
<row>
<entry>8.0.0</entry>
<entry>
Для значения возврата добавили поддержку типа <type>mixed</type>.
</entry>
</row>
<row>
<entry>8.0.0</entry>
<entry>
Для значения возврата добавили поддержку типа <type>static</type>.
</entry>
</row>
<row>
<entry>8.0.0</entry>
<entry>
Добавили поддержку объединения типов.
</entry>
</row>
<row>
<entry>7.4.0</entry>
<entry>
Добавили поддержку типизации свойств классов.
</entry>
</row>
<row>
<entry>7.2.0</entry>
<entry>
Для значения возврата добавили поддержку типа <type>object</type>.
</entry>
</row>
<row>
<entry>7.1.0</entry>
<entry>
Для значения возврата добавили поддержку типа <type>iterable</type>.
</entry>
</row>
<row>
<entry>7.1.0</entry>
<entry>
Для значения возврата добавили поддержку типа <type>void</type>.
</entry>
</row>
<row>
<entry>7.1.0</entry>
<entry>
Для значения возврата добавили поддержку обнуляемого типа.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect2>
<sect2 xml:id="language.types.declarations.base">
<title>Атомарные типы</title>
<simpara>
Атомарные типы ведут себя прямолинейно, но с рядом оговорок,
которые описывает этот раздел.
</simpara>
<sect3 xml:id="language.types.declarations.base.scalar">
<title>Скалярные типы</title>
<warning>
<para>
Псевдонимы имён для скалярных типов, к которым относятся типы <type>bool</type>, <type>int</type>,
<type>float</type> и <type>string</type>, не поддерживаются.
Вместо назначения псевдонимов названия классов и интерфейсов трактуются как типы.
Например, буквальное название <literal>boolean</literal> в объявлении типа потребует,
чтобы значение выполняло условие &instanceof; в отношении класса или интерфейса
<literal>boolean</literal>, а не принадлежало типу <type>bool</type>:
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
function test(boolean $param) {}
test(true);
?>
]]>
</programlisting>
&example.outputs.8;
<screen>
<![CDATA[
Warning: "boolean" will be interpreted as a class name. Did you mean "bool"? Write "\boolean" to suppress this warning in /in/9YrUX on line 2
Fatal error: Uncaught TypeError: test(): Argument #1 ($param) must be of type boolean, bool given, called in - on line 3 and defined in -:2
Stack trace:
#0 -(3): test(true)
#1 {main}
thrown in - on line 2
]]>
</screen>
</informalexample>
</warning>
</sect3>
<sect3 xml:id="language.types.declarations.void">
<title>Тип void</title>
<note>
<para>
Возврат по ссылке из <type>void</type>-функции устарел начиная с PHP 8.1.0,
поскольку такая функция противоречива.
Раньше при вызове такой функции уже выдавалась ошибка уровня <constant>E_NOTICE</constant>:
<computeroutput>Только ссылки на переменные должны возвращаться по ссылке</computeroutput>.
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
function &test(): void {}
?>
]]>
</programlisting>
</informalexample>
</para>
</note>
</sect3>
<sect3 xml:id="language.types.declarations.base.function">
<title>Тип Callable</title>
<para>
Свойствам класса нельзя объявлять тип callable.
</para>
<note>
<simpara>
Тип callable нельзя указывать как название функции.
</simpara>
</note>
</sect3>
<sect3 xml:id="language.types.declarations.references">
<title>Объявление типов параметрам, которые принимают ссылку</title>
<simpara>
Параметр, который принимает ссылку, проверяет
тип переменной <emphasis>только</emphasis> при входе в функцию, в начале вызова,
но не при возврате из функции,
поэтому в функции возможно изменение типа ссылки на переменную.
</simpara>
<example>
<title>Типизированный параметр, который принимает ссылку</title>
<programlisting role="php">
<![CDATA[
<?php
function array_baz(array &$param)
{
$param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>
]]>
</programlisting>
&example.outputs.similar;
<screen>
<![CDATA[
int(1)
Fatal error: Uncaught TypeError: array_baz(): Argument #1 ($param) must be of type array, int given, called in - on line 9 and defined in -:2
Stack trace:
#0 -(9): array_baz(1)
#1 {main}
thrown in - on line 2
]]>
</screen>
</example>
</sect3>
</sect2>
<sect2 xml:id="language.types.declarations.composite">
<title>Примечание по составным типам</title>
<para>
На объявления составных типов распространяется ряд ограничений;
компилятор выполняет проверку избыточности типов,
чтобы предотвратить простые ошибки.
</para>
<caution>
<simpara>
Комбинирование пересечений и объединений типов оставалось невозможным
до PHP 8.2.0 и введения DNF-типов.
</simpara>
</caution>
<sect3 xml:id="language.types.declarations.composite.union">
<title>Объединение типов</title>
<warning>
<simpara>
Невозможно определить в объединённом типе два одноэлементных типа <type>false</type> и <type>true</type>.
Вместо этого указывают тип <type>bool</type>.
</simpara>
</warning>
<caution>
<simpara>
До PHP 8.2.0 запрещали определять типы <type>false</type> и <type>null</type> отдельно,
поэтому объединение типов, которое состояло только из этих типов, оставалось недопустимым.
К таким объединениям относятся типы: <type>false</type>, <literal>false|null</literal>
и <literal>?false</literal>.
</simpara>
</caution>
<sect4 xml:id="language.types.declarations.nullable">
<title>Синтаксический сахар обнуляемого типа</title>
<para>
Объявление отдельного базового типа помечают как nullable путём
добавления к типу префикса в виде
вопросительного знака (<literal>?</literal>).
Поэтому типы <literal>?T</literal> и <literal>T|null</literal> идентичны.
</para>
<note>
<simpara>
Этот синтаксис поддерживается с PHP 7.1.0
и предшествует поддержке объединения типов.
</simpara>
</note>
<note>
<para>
Ещё один способ объявить nullable-параметр —
указать значением по умолчанию значение <literal>null</literal>.
Объявлять тип таким способом не рекомендуют, поскольку изменение значения по умолчанию
в дочернем классе нарушит совместимость типов,
и к объявлению типа потребуется добавить тип <type>null</type>.
Это поведение также устарело начиная с PHP 8.4.
</para>
<example>
<title>Старый способ указать nullable-параметр</title>
<programlisting role="php">
<![CDATA[
<?php
class C {}
function f(C $c = null)
{
var_dump($c);
}
f(new C());
f(null);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
object(C)#1 (0) {
}
NULL
]]>
</screen>
</example>
</note>
</sect4>
</sect3>
<sect3 xml:id="language.types.declarations.composite.redundant">
<title>Повторные и избыточные типы</title>
<para>
Правила объявления составных типов предусматривают ряд ограничений.
При компиляции кода с избыточными типами, которые возможно обнаружить без загрузки классов,
возникнет ошибка. Примеры ошибок в объявлениях составных типов включают:
<itemizedlist>
<listitem>
<simpara>
Повторение типа в объявлениях наподобие <literal>int|string|INT</literal>
или <literal>Countable&amp;Traversable&amp;COUNTABLE</literal> вызовет ошибку,
поскольку после разрешения названия типа внутренними средствами языка тип встретится больше одного раза.
</simpara>
</listitem>
<listitem>
<simpara>
Объявление типа <type>mixed</type> или <type>never</type> с другими типами вызовет ошибку.
</simpara>
</listitem>
<listitem>
<simpara>Ошибки объединения типов:</simpara>
<itemizedlist>
<listitem>
<simpara>
Избыточное объявление типа <type>false</type> или <type>true</type>
вместе с типом <type>bool</type>.
</simpara>
</listitem>
<listitem>
<simpara>
Избыточное объявление типа класса вместе с типом <type>object</type>.
</simpara>
</listitem>
<listitem>
<simpara>
Избыточное объявление типа <type>array</type> или <classname>Traversable</classname>
вместе с типом <type>iterable</type>.
</simpara>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<simpara>Ошибки пересечения типов:</simpara>
<itemizedlist>
<listitem>
<simpara>
Объявление типа, который не относится к классовому типу.
</simpara>
</listitem>
<listitem>
<simpara>
Объявление типа <type>self</type>, <type>parent</type>
или <type>static</type>.
</simpara>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<simpara>Ошибки объявления <acronym>DNF</acronym>-типов:</simpara>
<itemizedlist>
<listitem>
<simpara>
Избыточное объявление более строго типа с более общим типом.
</simpara>
</listitem>
<listitem>
<simpara>
Объявление дубликатов в пересечении типов.
</simpara>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</para>
<note>
<simpara>
Эти проверки не гарантируют, что тип «минимален» и не содержит повторений или избыточных типов,
поскольку для этого потребовалось бы загрузить все указанные типы классов.
</simpara>
</note>
<para>
Например, если типы <literal>A</literal> и <literal>B</literal> — псевдонимы классов,
то составной тип <literal>A|B</literal> остаётся корректным объединением типов,
даже если тип получится свести либо к <literal>A</literal>, либо к <literal>B</literal>.
Аналогично, если класс <code>B extends A {}</code>, то составной тип <literal>A|B</literal> также относится
к корректному объединению типов, даже если тип получится свести только к типу <literal>A</literal>.
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
function foo(): int|INT {} // Запрещено
function foo(): bool|false {} // Запрещено
function foo(): int&Traversable {} // Запрещено
function foo(): self&Traversable {} // Запрещено
use A as B;
function foo(): A|B {} // Запрещено (оператор "use" только создаёт псевдоним через механизм разрешения имён, а не отдельный тип)
function foo(): A&B {} // Запрещено (оператор "use" только создаёт псевдоним через механизм разрешения имён, а не отдельный тип)
class_alias('X', 'Y');
function foo(): X|Y {} // Разрешено (избыточность обнаружится только при выполнении кода)
function foo(): X&Y {} // Разрешено (избыточность обнаружится только при выполнении кода)
?>
]]>
</programlisting>
</informalexample>
</para>
</sect3>
</sect2>
<sect2 xml:id="language.types.declarations.examples">
&reftitle.examples;
<example>
<title>Пример объявления типа через название класса</title>
<programlisting role="php">
<![CDATA[
<?php
class C {}
class D extends C {}
// Класс не наследует класс C
class E {}
function f(C $c)
{
echo get_class($c)."\n";
}
f(new C);
f(new D);
f(new E);
?>
]]>
</programlisting>
&example.outputs.8;
<screen>
<![CDATA[
C
D
Fatal error: Uncaught TypeError: f(): Argument #1 ($c) must be of type C, E given, called in /in/gLonb on line 14 and defined in /in/gLonb:8
Stack trace:
#0 -(14): f(Object(E))
#1 {main}
thrown in - on line 8
]]>
</screen>
</example>
<example>
<title>Пример объявления типа через название интерфейса</title>
<programlisting role="php">
<![CDATA[
<?php
interface I
{
public function f();
}
class C implements I
{
public function f() {}
}
// Класс не реализует интерфейс I
class E {}
function f(I $i)
{
echo get_class($i) . "\n";
}
f(new C);
f(new E);
?>
]]>
</programlisting>
&example.outputs.8;
<screen>
<![CDATA[
C
Fatal error: Uncaught TypeError: f(): Argument #1 ($i) must be of type I, E given, called in - on line 13 and defined in -:8
Stack trace:
#0 -(13): f(Object(E))
#1 {main}
thrown in - on line 8
]]>
</screen>
</example>
<example>
<title>Пример объявления типа значения возврата</title>
<programlisting role="php">
<![CDATA[
<?php
function sum($a, $b): float
{
return $a + $b;
}
// Обратите внимание, что функция вернёт значение с типом float
var_dump(sum(1, 2));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
float(3)
]]>
</screen>
</example>
<example>
<title>Возврат объекта</title>
<programlisting role="php">
<![CDATA[
<?php
class C {}
function getC(): C
{
return new C();
}
var_dump(getC());
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
object(C)#1 (0) {
}
]]>
</screen>
</example>
<example>
<title>Объявление параметра с обнуляемым типом</title>
<programlisting role="php">
<![CDATA[
<?php
class C {}
function f(?C $c)
{
var_dump($c);
}
f(new C());
f(null);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
object(C)#1 (0) {
}
NULL
]]>
</screen>
</example>
<example>
<title>Объявление типа значения возврата как обнуляемого</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
function get_item(): ?string
{
if (isset($_GET['item'])) {
return $_GET['item'];
} else {
return null;
}
}
?>
]]>
</programlisting>
</example>
<example>
<title>Объявление типа свойства класса</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
class User
{
public static string $foo = 'foo';
public int $id;
public string $username;
public function __construct(int $id, string $username)
{
$this->id = $id;
$this->username = $username;
}
}
?>
]]>
</programlisting>
</example>
</sect2>
<sect2 xml:id="language.types.declarations.strict">
<title>Строгая типизация</title>
<para>
В нестрогом режиме, в котором проверка типов работает по умолчанию, PHP преобразовывает значения неправильного типа
в скалярный тип, который указали в объявлении, поэтому, например, при передаче в параметр с типом <type>string</type>
аргумента с типом <type>int</type> функция получит значение с типом <type>string</type>.
</para>
<para>
Строгий режим включается отдельно для каждого файла. В строгом режиме
механизм проверки типов признаёт только значения, которые соответствуют типу объявления,
иначе выбрасывается ошибка <classname>TypeError</classname>.
Единственное исключение из правила — значения с типом <type>int</type>,
которые передают в объявления типа <type>float</type>.
</para>
<warning>
<simpara>
Объявление директивы <literal>strict_types</literal> не влияет на вызовы функций внутри встроенных функций.
</simpara>
</warning>
<para>
Строгий режим включают инструкцией &declare; с объявлением
директивы <literal>strict_types</literal>:
</para>
<note>
<para>
На строгость проверки типов при вызове функций влияет режим,
который объявили <emphasis>внутри</emphasis> файла вызова,
а не режим, который установили в файле объявления функции.
Механизм проверки типов применит режим, который установили на стороне вызова,
и автоматически приведёт типы значений, если файл без строгой типизации
вызывает функцию, которую объявили в файле со строгой типизацией.
</para>
</note>
<note>
<para>
Строгая типизация определяется только для объявлений скалярных типов.
</para>
</note>
<example>
<title>Строгая типизация для значений аргументов</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
declare(strict_types=1);
function sum(int $a, int $b)
{
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>
]]>
</programlisting>
&example.outputs.8;
<screen>
<![CDATA[
int(3)
Fatal error: Uncaught TypeError: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 9 and defined in -:4
Stack trace:
#0 -(9): sum(1.5, 2.5)
#1 {main}
thrown in - on line 4
]]>
</screen>
</example>
<example>
<title>Приведение типов для значений аргументов</title>
<programlisting role="php">
<![CDATA[
<?php
function sum(int $a, int $b)
{
return $a + $b;
}
var_dump(sum(1, 2));
// Механизм проверки типов приведёт значения аргументов к целым числам: обратите внимание на вывод!
var_dump(sum(1.5, 2.5));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
int(3)
int(3)
]]>
</screen>
</example>
<example>
<title>Строгая типизация для значений возврата</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
declare(strict_types=1);
function sum($a, $b): int
{
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1, 2.5));
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
int(3)
Fatal error: Uncaught TypeError: sum(): Return value must be of type int, float returned in -:5
Stack trace:
#0 -(9): sum(1, 2.5)
#1 {main}
thrown in - on line 5
]]>
</screen>
</example>
</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
-->