PHP入門 | 構造化とオブジェクト指向 | 継承による機能拡張

オブジェクト指向では、作成したクラスをさまざまな場所で再利用できる。しかし実際に使おうとすると、「ここをこのように作り直して使いたい」や「これは機能として少し足りないので、もっと拡張したい」といったことも出てくる。

そのような場合にクラスのコードを書き換えて変更するのも1つの方法だが、大きなプロジェクトで多くの場所ですでに使われている場合、勝手にクラスの内容を変更するわけにはいかない。かといって、クラスのコードをコピーしてさらに新しいクラスを作るのは無駄である。ほとんど同じで一部だけ少し違うクラスをいくつも作るのは、コードの浪費である。

元のクラスには触れず、最小限の修正だけでクラスを再利用できるようにするという考え方をもとに作られたのが「継承」という概念である。

継承は、すでにあるクラスの機能をそのまますべて引き継いで新しいクラスを作るものである。これは次のようにクラスを定義して利用できる。

class クラス名 extends 継承するクラス {...}

継承元になるクラスを「スーパークラス」、継承して新しく作ったクラスを「サブクラス」と呼ぶ。サブクラスはスーパークラスのすべてのフィールドやメソッドを引き継ぎ、そのまま使用できる。ただし、アクセスキーワードがprivateになっているものは隠されているため使用できない。

次は、以前の例をさらに修正したものである。

<?php
class TextModify {
    private $header = "<b>";
    private $footer = "</b>";
    private $body = "";
    private $find = "PHP";
     
    public function __construct($h,$f){
        $this->setHeader($h);
        $this->setFooter($f);
    }
     
    function setHeader($s){
        $this->header = $s;
    }
     
    function setFooter($s){
        $this->footer = $s;
    }
     
    function setBody($s){
        $this->body = htmlspecialchars(strtoupper($s));
    }
    function setFind($s){
        $this->find = $s;
    }
     
    function getRenderText(){
            $res = str_replace($this->find, $this->header . $this->find . $this->footer, $this->body);
        return $res;
    }
     
    function writeRenderText(){
        echo $this->getRenderText();
    }
}
 
class TitleModify extends TextModify {
     
    public function __construct($s){
        $this->setHeader('<span style="color:red;">');
        $this->setFooter('</span>');
        $this->setFind('PHP');
        $this->setBody($s);
    }
}
 
class MsgModify extends TextModify {
     
    public function __construct($s){
        $this->setHeader('<span style="color:blue;">');
        $this->setFooter('</span>');
        $this->setFind('PHP');
        $this->setBody($s);
    }
}
 
class RepModify extends TextModify {
     
    public function __construct($s){
        $this->setHeader('<b>');
        $this->setFooter('</b>');
        $this->setFind('PHP');
        $this->setBody($s);
    }
}
 
// インスタンスを準備
$title_obj = new TitleModify('Hello PHP!');
$msg_obj = new MsgModify('ここにPHPという文字を含む文章を書いてください。');
if ($_POST != null){
    $str = $_POST['text1'];
    $rep_obj = new RepModify($str);
}
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1><?php $title_obj->writeRenderText(); ?></h1>
        <p><?php $msg_obj->writeRenderText(); ?></p>
        <hr>
        <p><?php if (isset($rep_obj)) $rep_obj->writeRenderText(); ?></p>
        <form method="post" action="./index.php">
            <textarea name="text1" cols="40" rows="5"><?php echo $str; ?></textarea>
            <br><input type="submit">
        </form>
        <hr>
    </body>
</html>

ここではTextModifyクラスを継承して、TitleModifyMsgModifyRepModifyというサブクラスを作った。各クラスではそれぞれ__constructを用意し、必要な設定ができるようにしている。

これらのサブクラスにはコンストラクタしかないが、その中で各フィールドの値をアクセスメソッドで設定しており、実際の利用ではwriteRenderTextで出力している。スーパークラスTextModifyの機能をそのまま使えることがわかる。

このようにクラスを継承して機能をさらに拡張しながら再利用することで、より柔軟にクラスを作成できるようになる。