1
0
mirror of https://github.com/php/doc-ja.git synced 2026-03-27 00:22:08 +01:00
Files
archived-doc-ja/language/types/declarations.xml
2025-10-04 07:12:16 +09:00

811 lines
22 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 0ece873cecfc4dacd14e8bebbec12c6e00de56a0 Maintainer: mumumu Status: ready -->
<sect1 xml:id="language.types.declarations">
<title>型宣言</title>
<para>
関数のパラメータや戻り値、
クラスのプロパティ (PHP 7.4.0 以降)、クラス定数 (PHP 8.3.0 以降) に対して型を宣言することができます。
これによって、その値がコール時に特定の型であることを保証できます。
その型でない場合は、<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>
union 型のサポートが追加されました。
</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>
nullable な型のサポートが追加されました。
</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> を使った場合、
値が <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 以降は推奨されなくなりました。
なぜなら、関数の定義そのものが矛盾しているからです。
PHP 8.1.0 より前のバージョンでは、
関数をコールした際に次のような <constant>E_NOTICE</constant> が発生していました:
<computeroutput>Only variable references should be returned by reference</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>
この型は、クラスのプロパティの型宣言では使うことができません。
</para>
<note>
<simpara>
関数のシグネチャに指定することもできません。
</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 より前のバージョン、
つまり <acronym>DNF</acronym> 型がサポートされる前は、
交差型とunion型を組み合わせることはできませんでした。
</simpara>
</caution>
<sect3 xml:id="language.types.declarations.composite.union">
<title>union 型</title>
<warning>
<simpara>
union 型の中で、シングルトン型 <type>true</type>
<type>false</type> を同時に組み合わせて使うことはできません。
<type>bool</type> 型を使ってください。
</simpara>
</warning>
<caution>
<simpara>
PHP 8.2.0 より前のバージョンでは、
&false;<type>null</type> 型は
独立した型として使えず、
union 型でそれらだけを指定することも許されませんでした。
つまり、&false;, <literal>false|null</literal>,
<literal>?false</literal> のような型はいずれも許されませんでした。
</simpara>
</caution>
<sect4 xml:id="language.types.declarations.nullable">
<title>nullable な型とシンタックスシュガー</title>
<para>
単一の基本型を宣言した場合、
型の名前の前にクエスチョンマーク (<literal>?</literal>) を付けることで、nullable であるという印を付けることができます。
よって、<literal>?T</literal><literal>T|null</literal> は同じ意味です。
</para>
<note>
<simpara>
この文法は、PHP 7.1.0 以降でサポートされており、
一般化された union 型がサポートされる前から存在します。
</simpara>
</note>
<note>
<para>
デフォルト値に <literal>null</literal> を指定することで、
null を許容するパラメータを指定することができます。
これは、子クラスでデフォルト値が変更された場合にクラスの互換性が壊れ、
型宣言で <type>null</type>
型を追加しなければならなくなるため、おすすめできません。
この振る舞いは、PHP 8.4 以降は推奨されなくなっています。
</para>
<example>
<title>引数にnullを許容する古いやり方</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>union 型に適用される制限:</simpara>
<itemizedlist>
<listitem>
<simpara>
<type>bool</type> 型が使われている場合、<type>false</type>
<type>true</type> 型は追加で使えません。
</simpara>
</listitem>
<listitem>
<simpara>
<type>object</type> 型が使われている場合、クラス型は追加で使えません。
</simpara>
</listitem>
<listitem>
<simpara>
<type>iterable</type> 型が使われている場合、
<type>array</type><classname>Traversable</classname>
は追加で使えません。
</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> のみに縮めることができますが、
正しい union 型です。 同様に、<code>B extends A {}</code>
というクラスがあった場合、 <literal>A|B</literal>
<literal>A</literal> のみに縮めることができますが、
正しい union 型です。
<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>Null を許容する型宣言</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>Null を許容する戻り値の型宣言</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>
<!-- TODO Move this into its own declare page -->
<sect2 xml:id="language.types.declarations.strict">
<title>厳密な型付け</title>
<para>
デフォルトでは、PHP は誤った型の値を
可能であれば期待されたスカラー型の宣言に従うよう自動的に変換します(coercive モード)。
たとえば、関数に <type>int</type> が与えられたが、
パラメータで文字列が期待されていた場合、文字列型の値を取得します。
</para>
<para>
ファイルごとに strict モードを有効にすることができます。
strict モードでは、型宣言に正確に対応する値のみを受け入れ、
それ以外の値の場合、<classname>TypeError</classname> がスローされます。
このルールに関する唯一の例外は、<type>int</type> の値が
<type>float</type> 型の宣言に渡せることだけです。
</para>
<warning>
<simpara>
内部関数の中からの関数呼び出しは、
<literal>strict_types</literal> 宣言の影響を受けません。
</simpara>
</warning>
<para>
strict モードを有効にするには、&declare; 文を <literal>strict_types</literal> 宣言と一緒に使います。
</para>
<note>
<para>
厳密な型付けは、strict モードが有効になったファイルの
<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
-->