親クラスのプロパティの値を参照したいことがある。
特に、デフォルトの設定値をクラスごとに設定する場合など。
<?php
class A
{
public $config = ['prop1' => 'A', 'prop2' => 'A', 'prop3' => 'A', 'prop4' => 'A'];
}
class B extends A
{
public $config = ['prop1' => 'B', 'prop2' => 'B', 'prop3' => 'B'];
}
class C extends B
{
public $config = ['prop1' => 'C', 'prop2' => 'C'];
}
class D extends C
{
public $config = ['prop1' => 'D'];
}
$d = new D();
var_dump($d->config);
実行結果
array(1) {
["prop1"]=>
string(1) "D"
}
親クラスに ['prop2' => 'C']
が設定されてようがされてなかろうが、
class D
に書かれた$config
しか参照できない。
それでは困るので、解決策。
<?php
class A
{
public $config = ['prop1' => 'A', 'prop2' => 'A', 'prop3' => 'A', 'prop4' => 'A'];
}
class B extends A
{
public $config = ['prop1' => 'B', 'prop2' => 'B', 'prop3' => 'B'];
}
class C extends B
{
public $config = ['prop1' => 'C', 'prop2' => 'C'];
}
class D extends C
{
public $config = ['prop1' => 'D'];
}
$d = new D();
// 現在のクラス名を取得
$class = get_class($d);
while (true) {
$parent = get_parent_class($class);
echo $parent."\n"; // 親クラスの名前
if (!$parent) {
break;
}
$parents[] = $parent;
$class = $parent;
}
foreach ($parents as $parent) {
$vars = get_class_vars($parent);
var_dump($vars); // 結果を出力
}
結果がこちら。
array(1) {
["config"]=>
array(2) {
["prop1"]=>
string(1) "C"
["prop2"]=>
string(1) "C"
}
}
array(1) {
["config"]=>
array(3) {
["prop1"]=>
string(1) "B"
["prop2"]=>
string(1) "B"
["prop3"]=>
string(1) "B"
}
}
array(1) {
["config"]=>
array(4) {
["prop1"]=>
string(1) "A"
["prop2"]=>
string(1) "A"
["prop3"]=>
string(1) "A"
["prop4"]=>
string(1) "A"
}
}
これで取得できる!
ただし、merge された状態での取得はできない。
ということで、何も考えずに勝手にconfig
がマージされるtrait を作ってみた。
<?php
trait configMerger
{
public function __construct()
{
$class = get_class($this);
$classes[] = $class;
while (true) {
$parent = get_parent_class($class);
if (!$parent) {
break;
}
$classes[] = $parent;
$class = $parent;
}
foreach ($classes as $class) {
$vars = get_class_vars($class);
$this->config += $vars['config'];
}
}
}
class A
{
use configMerger;
public $config = ['prop1' => 'A', 'prop2' => 'A', 'prop3' => 'A', 'prop4' => 'A'];
}
class B extends A
{
public $config = ['prop1' => 'B', 'prop2' => 'B', 'prop3' => 'B'];
}
class C extends B
{
public $config = ['prop1' => 'C', 'prop2' => 'C'];
}
class D extends C
{
public $config = ['prop1' => 'D'];
}
$d = new D();
var_dump($d->config);
結果は、
array(4) {
["prop1"]=>
string(1) "D"
["prop2"]=>
string(1) "C"
["prop3"]=>
string(1) "B"
["prop4"]=>
string(1) "A"
}
となり、ちゃんとマージされたconfig
が取得できた。
ちなみに、この例では、 classA
の中で use configMerger;
を書いているが、
class A
がライブラリのコードで触ることができない場合、
class D
にuse configMerger;
を書いても同じ挙動を期待できる。
あまり使う機会はないかと思うが、古いライブラリとかを使う時に知っておくと便利かもしれないtipsでした。