普通の継承 子→親参照
参照というよりは、子クラスに $parentName が(継承されて)定義されているだけの状態
<?php
class ParentClass1
{
protected string $parentName = "parent\n";
}
class ChildClass1 extends ParentClass1
{
public function getParentName(): void
{
echo $this->parentName;
}
}
$child = new ChildClass1;
$child->getParentName();
parent
静的な参照 parentとselfの違い
<?php
class ParentClass2
{
protected static string $parentName = "parent\n";
}
class ChildClass2 extends ParentClass2
{
public static function getParentName(): void
{
// parent::$parentName と self::$parentName は同一の存在
echo "test1:" . parent::$parentName;
echo "test2:" . self::$parentName; // 定義を継承している = 自身のプロパティとして parentName を持っている
self::$parentName = "child\n"; // 代入
echo "test3:" . parent::$parentName;
echo "test4:" . self::$parentName; // 定義を継承している = 自身のプロパティとして parentName を持っている
}
}
ChildClass2::getParentName();
test1:parent
test2:parent
test3:child
test4:child
<?php
class ParentClass3
{
protected static string $parentName = "parent\n";
}
class ChildClass3 extends ParentClass3
{
protected static string $parentName = "child\n"; // ChildClass2 との違い
public static function getParentName ()
{
// 子クラスに同名プロパティを定義したとき、
// parent::$parentNameとself::$parentNameは別物になる
echo "test1:" . parent::$parentName;
echo "test2:" . self::$parentName; // 自身のプロパティとして parentName を持っている
self::$parentName = "child2\n"; // 代入
echo "test3:" . parent::$parentName;
echo "test4:" . self::$parentName; // 自身のプロパティとして parentName を持っている
}
}
ChildClass3::getParentName();
test1:parent
test2:child
test3:parent
test4:child2
普通の継承:親から子のプロパティを参照するということ(前置き)
ex1.phpと同じ
参照というよりは、子クラスに parentFunction() が(継承されて)定義されているだけの状態
<?php
class ParentClass4
{
protected string $name = "parent\n";
protected function parentFunction(): void
{
echo $this->name;
}
}
class ChildClass4 extends ParentClass4
{
protected string $name = "child\n";
public function callParentFunction(): void
{
$this->parentFunction();
}
}
$child = new ChildClass4;
$child->callParentFunction();
child
静的な参照 self が指すものと遅延静的束縛
selfはその持ち主のメソッドやプロパティを、
staticは子の持つメソッドやプロパティを参照可能にする
<?php
class ParentClass5
{
protected static string $name = "parent\n";
protected static function parentFunction(): void
{
echo self::$name;
echo static::$name; // 遅延静的束縛
}
}
class ChildClass5 extends ParentClass5
{
protected static string $name = "child\n";
public static function callParentFunction(): void
{
// parent::parentFunction と self::parentFunction の状況は
// ex2_1.php, ex2_2.php を参照
self::parentFunction();
}
}
ChildClass5::callParentFunction();
parent
child
<?php
class ParentClass6
{
protected static string $name = "parent\n";
protected static function parentFunction(): void
{
echo self::$name;
echo static::$name; // 遅延静的束縛
}
}
class ChildClass6 extends ParentClass6
{
protected static string $name = "child\n";
protected static function parentFunction(): void // ex3_2.php との違い
{
echo self::$name;
echo static::$name;
}
public static function callParentFunction(): void
{
// parent::parentFunction と self::parentFunction の状況は
// ex2_1.php, ex2_2.php を参照
self::parentFunction();
}
}
ChildClass6::callParentFunction();
child
child
親が子クラスの protected を利用できる ということ
相互参照できるとは書かれていても、使いどころも少ないのであまり詳細は見かけないかも
# Factory パターンとかで使えなくもなさそうだけど、他にやりようはあるし…
よくある誤解
# PHPだからね
<?php
class ParentClass7
{
public function getChildName(): void
{
echo $this->name;
}
}
class ChildClass7 extends ParentClass7
{
protected string $name = "child\n";
}
$parent = new ParentClass7;
$parent->getChildName(); // ""
$parent->name = "parent_name";
var_dump($parent); // 親クラスに public の新たなプロパティが追加された
$parent->getChildName(); // 動くようになるが、子クラスの定義は関係ない
object(ParentClass7)#1 (1) {
["name"]=>
string(11) "parent_name"
}
parent_name
インスタンスで見ると直接的な関係が無くても extends があれば protected が読め、なければ読めない
<?php
class ParentClass8
{
public function getChildName(): void
{
$child = new ChildClass8; // この ChildClass のインスタンス($child)と自身($parent)に直接的な関係がなさそうでも、
echo $child->name; // 定義上親子であれば子の protected は参照できる
}
public function callChildFunction(): void
{
ChildClass8::childFunction(); // インスタンスじゃなくても。
}
}
class ChildClass8 extends ParentClass8
{
protected string $name = "child\n";
protected static function childFunction(): void
{
echo "child_function\n";
}
}
$parent = new ParentClass8;
$parent->getChildName();
$parent->callChildFunction();
child
child_function
<?php
class ParentClass9
{
public function getChildName(ChildClass9 $child): void
{
echo $child->name; // 定義上親子であれば子のprotectedは参照できる
}
public function callChildFunction(ChildClass9 $child): void
{
$child->childFunction();
}
}
class ChildClass9 extends ParentClass9
{
protected string $name = "child\n";
protected function childFunction(): void
{
echo "child_function\n";
}
}
$parent = new ParentClass9;
$child = new ChildClass9;
$parent->getChildName($child); // この ChildClass のインスタンス($child)と自身($parent)に直接的な関係がなさそうでも
$parent->callChildFunction($child);
child
child_function
extends がなければもちろん読めない
<?php
class ParentClass10
{
public static function getChildName(): void
{
$child = new ChildClass10;
echo $child->name;
}
public static function callChildFunction(): void
{
ChildClass10::childFunction();
}
}
class ChildClass10 /* extends ParentClass10 */
{
protected string $name = "child\n";
protected static function childFunction(): void
{
echo "child_function\n";
}
}
ParentClass10::getChildName();
Error: Cannot access protected property ChildClass10::$name
余談
同じクラスの private は、インスタンスが分かれていても読むことができる
<?php
class Test
{
private string $name = "";
public function __construct(string $name = "")
{
$this->name = $name;
}
public function getName(Test $instance): void
{
echo $instance->name;
}
}
$instanceA = new Test("A");
$instanceB = new Test("B");
$instanceA->getName($instanceB);
B
他の言語でも大体同じなので試してみてね