見出し画像

オーバーライド

オーバライド → サブクラス特融の処理があったときに、親クラスが持つメソッドをサブクラス側で「上書き」または「拡張」したい場合に実現する。

◇オーバロードPHP上ではできない◇
親クラスの引数または戻り値を変更して同じ名前のメソッドを作ること → オーバーロード
たとえば、、、
親クラスと子クラスで引数の数が違うためエラーになる

<?php
// 親
abstract class Clock
{
    public function setTime($item)
    {
        // 何らかの処理
    }
} 
// 子
class DigitalClock extends Clock
{
    public function setTime($item, $fontColor)
    {
        // デジタル時計特有の何らかの処理
    }
}

※オーバーロードに近いことを実現するには →
あらかじめ親クラスのメソッドに余白の引数をもたせる。
例 ↓

<?php declare(strict_types=1); ?>
<?php
// ーーーーーー 時計クラス(親クラス)ーーーーーーー
abstract class Clock
{
    public function setTime(string $time, $extraArguments = null)
    {
        // 何らかの処理
    }
}

// ーーーーーーーー デジタルクラス(子クラス)ーーーーーーーーー
class DigitalClock extends Clock
{
    public function setTime(string $time, $extraArguments = null)
    {
        // デジタル時計の特融処理
        // 引数を使って、文字色のデータを受け取る。
        echo 'デジタルクラスの第1引数は' .  $time . '第2引数は' .  $extraArguments['textColor'] . '<br>';
    }
}

// ーーーーーーーーー アナログクラス(子クラス)ーーーーーーーーーー
class AnalogClock extends Clock
{
    public function setTime(string $time, $extraArguments = null)
    {
        // アナログ時計特有の処理
        // 引数は無視する。
        echo 'アナログクラスの第1引数は' . $time . '第2引数は' . $extraArguments . '<br>';
    }
}

// ーーーーーーーーー メインルーチン ーーーーーーーーーーー
$digitalClock = new DigitalClock();
$digitalClock->setTime('11:14', ['textColor' => 'green']); // 引数2個

$analogClock = new AnalogClock();
$analogClock->setTime('11:14');  // 引数1個
?>

デジタルクラスの第1引数は11:14第2引数はgreen
アナログクラスの第1引数は11:14第2引数は
$extraArguments は何も指定していなければnullがデフォルト値になる。

◇継承におけるコンストラクタの扱い◇
継承時のコンストラクタの扱いは、メソッドと微妙に違う。
子クラスにコンストラクタを定義しなかった場合、
子クラスは親クラスのコンストラクタをそのまま引き継ぐ。

<?php declare(strict_types=1); ?>
<body>
<?php
// 親クラス
    class SuperClass
    {
        protected $datal;
        public function __construct(string $datal)
        {
            $this->datal = $datal;
            print $this->datal;
        }
    }
// 子クラス
    class SubClass extends SuperClass
    {
        // 特に何も記載なし
    }
// 子クラスに定義
    $subClass = new SubClass('This is datal');
?>
</body>

結果: This is datal

子クラスにコンストラクタを定義 → 親のコンストラクタを上書きする。
通常、メソッドであれば引数の定義を変えると(オーバーロード)文法エラーになる。
コンストラクターの場合はエラーにならない。

<?php declare(strict_types=1); ?>
<body>
<?php
// ------------- 親クラス ---------------
    class SuperClass
    {
        protected $data1;

        public function __construct(string $data1)
        {
            $this->data1 = $data1;
            print $this->data1;
        }
    }
// --------------- 子クラス -------------
    class SubClass extends SuperClass
    {
        protected $data2;

        public function __construct(string $data1, string $data2) // 親より1個多いい引数
        {
            $this->data1 = $data1;
            $this->data2 = $data2;
            print $this->data1. '<br>' .$this->data2 . '<br>' ;
        }
    }

// ------- メインルーチン ------------
    $subClass = new SubClass('this is datal' , 'this is data2');
    // $subClass = new SubClass('this is data1.');
    // 親クラスのコンストラクターは子クラスに上書きしてしまったためエラー(引数が足りない) ↑
?>
</body>

this is datal
this is data2

◇親クラスのメソッドを呼び出す◇
オーバーライドした子クラスのメソッド内部から、
親クラスが持つオーバーライド前のメソッドを呼び出したいときがある → parent
parent キーワード → オーバーライド前のメソッドをコールする
parent : : [ メソッド名 ](引数)

<?php declare(strict_types=1); ?>
<body>
<?php
// ------------- 親クラス -----------
    abstract class Clock
    {
        public function setTime(int $time) : void
        {
            print 'ClockクラスのsetTime()がよばれました。<br>';
        }
    }
// ------------- 子クラス -----------------
    class DigitalClock extends Clock
    {
        public function setTime(int $time) : void
        {
            print 'DigitalCLockクラスのsetTime()が呼ばれました。<br>';
 // 親クラスのsetTime()をコール
            parent::setTIme($time);
        }
    }
// -------------- メインルーチン ------------------------
    $currentTime = strtotime('2018-08-09 17:15');
    
    $digitalClock = new DigitalClock(); // 子クラス
    $digitalClock->setTime($currentTime);
?>
</body>

DigitalCLockクラスのsetTime()が呼ばれました。
ClockクラスのsetTime()がよばれました。


DigitalClockクラスのsetTime()の中から → ClockクラスのsetTime()をコールしている。
こうすることで、DigitalクラスのsetTime()は固有の処理をしつつ、親クラスが行っている共通の処理もそのまま生かすことができる。

◇親クラスのコンストラクタをコール◇
親クラスのコンストラクタをコール → parent : :__construct(引数)
初めに実行されるコンストラクタは、DigitalClock : : __construct
このコンストラクタでは →
まず自クラスが持つプロパティ$color をセットしたうえで、
親クラスのClockクラスのコンストラクタをコールしている。

<?php declare(strict_types=1); ?>
<body>
<?php
// -------------- 親クラス -------------
    abstract class Clock
    {
        private $time;

        public function __construct(int $time)
        {
            print 'Clockクラスのコンストラクタが呼ばれました<br>';
            $this->time = $time;
        }
    }
// -------------- 子クラス -------------
    class DigitalClock extends Clock
    {
        private $color;

        public function __construct(int $time, string $color)
        {
            print 'DigitalClockクラスのコンストラクタがよばれました。<br>';
            $this->color = $color;
            parent::__construct($time);
        }
    }


    $currentTime = strtotime('2018-08-09 17:15');
    $digitalClock = new DigitalClock($currentTime, 'yellow'); // 子クラス

?>
</body>

DigitalClockクラスのコンストラクタがよばれました。
Clockクラスのコンストラクタが呼ばれました

◇継承、オーバーライドさせない◇
継承を使うと、親クラスが持つpublic、protextedなメソッドを、
子クラスはオーバーライドすることで自由に上書きができてしまう。
しかし、必ずいいこととはいえない。。。
親クラスが持つ値チェックのためのメソッドをオーバーライドすることで、子クラス側で値チェックをスキップしてしまうこともある。
このような対策のために → final キーワード

¥¥¥¥¥¥コメント¥¥¥¥¥¥¥¥¥
なかなかWi-Fiが安定できず投稿ができず。。。
一応ぼちぼちやれてはいるんだなあこれが。。。
オーバーライドはよくきくけどオーバーロードはしらなかったかな。。。
仕事で大変だけど少しでもしなきゃね。。。。

この記事が気に入ったらサポートをしてみませんか?