1
0
mirror of https://github.com/php/doc-ja.git synced 2026-03-24 07:02:08 +01:00
Files
archived-doc-ja/language/oop5/properties.xml
2025-11-09 21:39:00 +09:00

442 lines
13 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 801e7a15e8c9ee2d16966487dc9058d992450b46 Maintainer: takagi Status: ready -->
<!-- CREDITS: mumumu -->
<sect1 xml:id="language.oop5.properties" xmlns="http://docbook.org/ns/docbook">
<title>プロパティ</title>
<para>
クラスのメンバ変数のことを <emphasis>プロパティ</emphasis> といいます。
それ以外に <emphasis>フィールド</emphasis>
などという呼びかたを見たことがあるかもしれません。
しかし、このマニュアルでは <emphasis>プロパティ</emphasis>
と呼ぶことにします。
プロパティは、少なくともひとつのキーワード
(たとえば <link linkend="language.oop5.visibility">アクセス権</link>
のキーワード、
<link linkend="language.oop5.static">static キーワード</link>
PHP 8.1.0 以降のみ <link linkend="language.oop5.properties.readonly-properties">readonly</link>) のあとに、
オプションの型宣言
(PHP 7.4 以降、但し <code>readonly</code> を除く)
を続け、
その後に通常の変数の宣言を続けます。
宣言時に初期値を設定することもできますが、
初期値は <link linkend="language.constants">定数</link> 値でなければなりません。
</para>
<note>
<para>
クラスのプロパティを宣言する代替の方法として、
<literal>var</literal> キーワードを使う方法があります。
</para>
</note>
<note>
<simpara>
<link linkend="language.oop5.visibility">アクセス権</link>
を宣言しない場合、プロパティを <literal>public</literal>
として宣言したとみなされます。
</simpara>
</note>
<para>
クラスのメソッドからstatic でないプロパティにアクセスするには
<literal>-&gt;</literal> (オブジェクト演算子) を使って
<varname>$this-&gt;property</varname> のようにします
(<literal>property</literal> のところにプロパティ名を指定します)。
staticプロパティへのアクセスには <literal>::</literal> (ダブルコロン)
を使って <varname>self::$property</varname> のようにします。
staticプロパティとそうでないプロパティの違いについては、
<link linkend="language.oop5.static">static キーワード</link> を参照ください。
</para>
<para>
クラスのメソッドがオブジェクトのコンテキストからコールされたときには、
擬似変数 <varname>$this</varname> が使えます。
<varname>$this</varname> は、呼び出し元のオブジェクトの値です。
</para>
<para>
<example>
<title>プロパティの宣言</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
class SimpleClass
{
public $var1 = 'hello ' . 'world';
public $var2 = <<<EOD
hello world
EOD;
public $var3 = 1+2;
// 無効なプロパティ宣言
public $var4 = self::myStaticMethod();
public $var5 = $myVar;
// 有効なプロパティ宣言
public $var6 = myConstant;
public $var7 = [true, false];
public $var8 = <<<'EOD'
hello world
EOD;
// アクセス権を付けない場合
static $var9;
readonly int $var10;
}
?>
]]>
</programlisting>
</example>
</para>
<note>
<para>
クラスやオブジェクトを操作するための便利な関数が用意されています。
<link linkend="ref.classobj">クラス/オブジェクト関数</link>
を参照ください。
</para>
</note>
<sect2 xml:id="language.oop5.properties.typed-properties">
<title>型宣言</title>
<para>
PHP 7.4.0 以降は、プロパティの定義に <xref linkend="language.types.declarations" /> を含めることができます。
但し、<literal>callable</literal> 型を除きます。
<example>
<title>型付きプロパティの例</title>
<programlisting role="php">
<![CDATA[
<?php
class User
{
public int $id;
public ?string $name;
public function __construct(int $id, ?string $name)
{
$this->id = $id;
$this->name = $name;
}
}
$user = new User(1234, null);
var_dump($user->id);
var_dump($user->name);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
int(1234)
NULL
]]>
</screen>
</example>
</para>
<para>
型付きプロパティは、アクセスする前に初期化しなければいけません。
初期化しないと、<classname>Error</classname> がスローされます。
<example>
<title>プロパティにアクセスする</title>
<programlisting role="php">
<![CDATA[
<?php
class Shape
{
public int $numberOfSides;
public string $name;
public function setNumberOfSides(int $numberOfSides): void
{
$this->numberOfSides = $numberOfSides;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getNumberOfSides(): int
{
return $this->numberOfSides;
}
public function getName(): string
{
return $this->name;
}
}
$triangle = new Shape();
$triangle->setName("triangle");
$triangle->setNumberofSides(3);
var_dump($triangle->getName());
var_dump($triangle->getNumberOfSides());
$circle = new Shape();
$circle->setName("circle");
var_dump($circle->getName());
var_dump($circle->getNumberOfSides());
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
string(8) "triangle"
int(3)
string(6) "circle"
Fatal error: Uncaught Error: Typed property Shape::$numberOfSides must not be accessed before initialization
]]>
</screen>
</example>
</para>
</sect2>
<sect2 xml:id="language.oop5.properties.readonly-properties">
<title>読み取り専用プロパティ</title>
<para>
PHP 8.1.0 以降では、<code>readonly</code>
を付けてプロパティを宣言できます。これによって、プロパティを初期化した後に値が変更されることを防止できます。
PHP 8.4.0 より前のバージョンでは、<literal>readonly</literal> プロパティは暗黙的に private-set であり、
同じクラス内からのみ書き込みが可能でした。
PHP 8.4.0 以降では、<literal>readonly</literal> プロパティは暗黙的に
<link linkend="language.oop5.visibility-members-aviz"><literal>protected(set)</literal></link> となり、
子クラスからも設定可能です。必要に応じて明示的に
オーバーライドすることもできます。
<example>
<title>読み取り専用プロパティの例</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
class Test {
public readonly string $prop;
public function __construct(string $prop) {
// 正しい初期化
$this->prop = $prop;
}
}
$test = new Test("foobar");
// 正しいプロパティの読み取り
var_dump($test->prop); // string(6) "foobar"
// 不正な再代入です。同じ値を代入することは問題ありません。
$test->prop = "foobar";
// Error: Cannot modify readonly property Test::$prop
?>
]]>
</programlisting>
</example>
<note>
<para>
readonly は、
<link linkend="language.oop5.properties.typed-properties">型付きプロパティ</link>
に対してのみ指定できます。
型の制約がないプロパティを読み取り専用にしたい場合、
<xref linkend="language.types.mixed" /> が使えます。
</para>
</note>
<note>
<para>
読み取り専用の static プロパティはサポートされていません。
</para>
</note>
</para>
<para>
読み取り専用プロパティは、一度しか初期化できません。
初期化できるのは、
そのプロパティが宣言された場所と同じスコープに限られます。
これらのルールから外れたプロパティへの代入や変更を行った場合、
<classname>Error</classname> 例外が発生します。
<example>
<title>読み取り専用プロパティの不正な初期化</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
class Test1 {
public readonly string $prop;
}
$test1 = new Test1;
// スコープ外からの不正な初期化
$test1->prop = "foobar";
// Error: Cannot initialize readonly property Test1::$prop from global scope
?>
]]>
</programlisting>
</example>
</para>
<note>
<para>
読み取り専用プロパティに対して、
明示的にデフォルト値を設定することはできません。
なぜなら、読み取り専用プロパティにデフォルト値を設定することは、
本質的に定数と同じであり、あまり役に立たないからです。
<informalexample>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
class Test {
// Fatal error: Readonly property Test::$prop cannot have default value
public readonly int $prop = 42;
}
?>
]]>
</programlisting>
</informalexample>
</para>
</note>
<note>
<para>
読み取り専用プロパティは、
一度初期化されると <function>unset</function> できません。
しかし、初期化する前であれば
プロパティを宣言した同一のスコープから unset することはできます。
</para>
</note>
<para>
プロパティの変更は、単純な代入にとどまりません。
次に示すプロパティへの変更例は、
すべて <classname>Error</classname> 例外が発生します:
<informalexample>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
class Test {
public function __construct(
public readonly int $i = 0,
public readonly array $ary = [],
) {}
}
$test = new Test;
$test->i += 1;
$test->i++;
++$test->i;
$test->ary[] = 1;
$test->ary[0][] = 1;
unset($test->ary[0]);
$ref =& $test->i;
$test->i =& $ref;
byRef($test->i);
foreach ($test as &$prop);
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
但し、プロパティが読み取り専用であっても、
そのプロパティの内部まで変更できなくなるわけではありません。
読み取り専用プロパティ内部のオブジェクト(またはリソース) は、
内部的に変更しても構いません:
<informalexample>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
class Test {
public function __construct(public readonly object $obj) {}
}
$test = new Test(new stdClass);
// 有効なオブジェクト内部の変更
$test->obj->foo = 1;
// 不正な再代入
$test->obj = new stdClass;
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
PHP 8.3.0 以降では、
読み取り専用プロパティは <link linkend="object.clone">__clone()</link> を使ったオブジェクトのクローン時に再初期化できるようになりました。
<example>
<title>読み取り専用プロパティとオブジェクトのクローン</title>
<programlisting role="php">
<![CDATA[
<?php
class Test1 {
public readonly ?string $prop;
public function __clone() {
$this->prop = null;
}
public function setProp(string $prop): void {
$this->prop = $prop;
}
}
$test1 = new Test1;
$test1->setProp('foobar');
$test2 = clone $test1;
var_dump($test2->prop); // NULL
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.oop5.properties.dynamic-properties">
<title>動的なプロパティ</title>
<para>
オブジェクトに対して、存在しないプロパティを代入しようとした場合、
PHP は自動的に対応するプロパティを作成します。
こうして作成された動的なプロパティは、
そのインスタンスで <emphasis>のみ</emphasis> 使えます。
</para>
<warning>
<simpara>
動的なプロパティは、PHP 8.2.0 以降は推奨されなくなりました。
代わりに、プロパティを宣言することを推奨します。
任意のプロパティの名前を扱うには、
クラスがマジックメソッド
<link linkend="object.get">__get()</link>
<link linkend="object.set">__set()</link> を実装すべきです。
動的なプロパティを使うための最終手段として、
アトリビュート <code>#[\AllowDynamicProperties]</code>
でクラスをマークすることができます。
</simpara>
</warning>
</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
-->