php講座

オブジェクト指向

オブジェクト

オブジェクトとは

データは複数の変数に格納されるが、それをまとまった塊として扱いたいことがある。たとえば会員制ショッピングサイトの会員データは

  • 会員番号
  • パスワード
  • 連絡先メールアドレス
  • 住所
  • 氏名

など多岐にわたっており、それらをプログラムコード中にバラバラに管理するのは面倒である。

複数のデータをまとめる手段としては「配列」があるが、配列は本来は同じ種類のデータをまとめるためのものであり、上記例のようにバラバラの属性を持ったデータをまとめるためのものではない。

配列はどこにどのようなデータが入っているかは仕様上は不明であり、それを知るにはソースを読み解かなければならない。それはプログラムの保守上とても厄介なことなのだ(配列本来の使い方なら、同種のデータが連なっているだけなので、問題ない)。

ということで複数のデータを明確な仕様に則して格納する仕組みが求められる。そうした仕組みで作られたデータの塊を「構造体」と呼ぶ。

データが特定の文脈でまとめられると、それに対する処理もそれに付随したものとして特定化されたものが求められた。関数は処理のみをパッケージングして独立させようとしたものだが、今度はデータとそれに付随した処理をパッケージングして独立させようとするのだ。

このようにまとまった意味を持ったデータ群とそれに付随する処理をパッケージングして独立させたものを「オブジェクト」と呼ぶ。

オブジェクトとクラス

オブジェクトはどのようなデータを持ち、どのような処理を持っているかが仕様上明確に確定されている。このオブジェクトの(プログラム側の)「仕様書」がクラスである(人間=プログラマ側の仕様書はクラスの仕様に則して別途作らなければならないし、簡単に作れる)。

オブジェクトを使うためにはまずはその元となるクラスを定義しなければならない。

クラス
プログラム内の仕様書・設計書
オブジェクト
仕様書(クラス)通りに作られたモノ
クラスの構成要素

クラスはデータ群と処理から構成される。クラスで定義されるデータ(変数)をメンバ変数と呼び、処理(関数)をメソッドと呼ぶ。

  • メンバ変数
  • メンバ変数
  • メンバ変数
  • メソッド
  • メソッド
  • メソッド
PHPでのクラス
class クラス名{
    [public/protected/private] $変数名;
    [public/protected/private] $変数名;
    [public/protected/private] $変数名;

    public function __construct(引数){//コンストラクタと呼ばれる特殊なメソッド
        処理内容;
    }
    [public/protected/private] function メソッド名(引数){
        処理内容;
    }
}
  • 名前
  • 加入期
  • 出身地
がデータとして必要なシステムを作るケース。
/*連想配列*/
$array_member['name'] = '高橋':
$array_member['generation'] = '5';
$array_member['from'] = '福井';
//$array_memberの中に何が入るかは「今コーディングしている」プログラマ任せ
//要素の中身も数も可変
/*クラス*/
class Member{
    private $name;
    private $generation;
    private $from;

    public __construct($name, $generation, $from){
    …
    }
    …
}
//↑ここまでは「仕様上」確定している
//↓プログラマはMemberクラスの仕様通りにそれを利用する
…
/*オブジェクト*/
$obj_member = new Member('高橋',5,'福井');
//定義されている変数は必ず使えるし、それ以外は使えない。

オブジェクトの利用

インスタンス化

オブジェクトはクラスをもとに(コンピュータシステムの元ではメモリ上に展開され)実体化されることによって利用できるようになる。この実体化を「インスタンス化」(英語にしただけだが)と呼ぶ。オブジェクトとインスタンスは同義である。

クラスがインスタンス化されるときにはクラス内で定義された特殊なメソッド(関数)である「コンストラクタ」によってメンバ変数の初期化(変数に具体的な値が最初に代入されること)が行われる。

$変数名 = new クラス名(引数);
コンストラクタ

コンストラクタはコンストラクタに与えられた引数などを用いてメンバ変数の初期化を行う。

class Member{
    //メンバ変数
    private $name;
    private $generation;
    private $from;

    //コンストラクタ(constructの前の「__」はアンダーバー二つ)
    public __construct($name, $generation, $from){
        $this->name = $name;             //引数で渡された$nameの値がメンバ変数の$nameに代入される
        $this->generation = $generation; //引数で渡された$generationの値がメンバ変数の$generationに代入される
        $this->from = $from;             //引数で渡された$fromの値がメンバ変数の$fromに代入される
    }
}

※「$this->変数名」はメンバ変数の変数名である事を示し、引数の$変数名と区別される。

メンバ変数・メソッドの利用

クラスで定義されたメンバ変数やメソッドはインスタンス化された後、利用できるようになる。

class Member{
    public $name;
    …
    public function getName($name){
        $this->name = $name;
    }
}
$member = new Member('高橋');
print $member->name;      //「高橋」と出力
print $member->getName(); //「高橋」と出力
カプセル化

メンバ変数やメソッドはオブジェクトの外で利用できるものと外部から呼び出せないものとがある。それを決めているのがアクセス修飾子である。

アクセス修飾子

メンバ変数やメソッドのどれが外から使用可能で、どれが不可能かを制御することができる。オブジェクトの特定の属性を外部から制御できなくする仕掛けをカプセル化と呼ぶ。たとえばメンバ変数の$nameは一度初期化したら変更できないときには$nameをprivateに設定する(これが配列にはできない、$nameがソースの中でいつの間にか変更されている可能性を除去できない)。

このようなprivateのように外部からのアクセス可能性を制御するための修飾子をアクセス修飾子という。

private
クラスの内部でのみ利用でき、外部からは呼び出せない。
protected
クラスの内部とサブクラスからの未利用できる(本講では扱わない)。
public
クラスの外からも呼び出せる。
class Member{
    private $name;
    …
    public function getName($name){
        $this->name = $name;
    }
}
$member = new Member('高橋');
print $member->name;      //エラー
print $member->getName(); //(上のエラーがなければ)「高橋」と出力

使用例

member.class
<?php
class Member{
     // メンバ変数
     // Memberクラス全体のスコープを持つ
    /*
     * メンバー氏名
     */
    private $name;
    /*
     * 加入期
     */
    private $generation;
    /*
     * 出身地
     */
    private $from;
    /*
     * 役職
     */
    private $post;

     // コンストラクタ
     // Memberクラスを「実体化」する際に初期化を行う
    /*
     * コンストラクタ
     * @param string $name メンバー氏名
     * @param int $generation 加入期
     * @param string $from 出身地
     * @param string $post 役職
     */
    public function Member($name, $generation, $from, $post){
        $this->name = $name;
        $this->generation = $generation;
        $this->from = $from;
        $this->post = $post;
    }

     // メンバメソッド
     // クラス内で使用できる「関数」
     // 主にメンバ変数に依存した処理を担当する
    /*
     * 名前を取得する
     * @return string
     */
    public function getName(){
        return $this->name;
    }
    /*
     * 加入期を取得する
     * @return int
     */
    public function getGeneration(){
        return $this->generation;
    }
    /*
     * 出身地を取得する
     * @return string
     */
    public function getFrom(){
        return $this->from;
    }
    /*
     * 役職を取得する
     * @return string
     */
    public function getPost(){
        return $this->post;
    }
    /*
     * 役職を設定する
     * @param string $post
     */
    public function setPost($post){
        $this->post = $post;
    }
}
?>
object1.php
<?php
require_once('member.class');

// new コンストラクタ()でオブジェクトが実体化される
$members[] = new Member('高橋愛',5,'福井','リーダー');
$members[] = new Member('新垣里沙',5,'横浜','サブリーダー');
$members[] = new Member('亀井絵里',6,'東京','');
$members[] = new Member('道重さゆみ',6,'山口','');
$members[] = new Member('田中れいな',6,'福岡','');
$members[] = new Member('久住小春',7,'新潟','');
$members[] = new Member('光井愛佳',8,'滋賀','');
$members[] = new Member('ジュンジュン',8,'中国','留学生');
$members[] = new Member('リンリン',8,'中国','留学生');
?>
<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8" />
   <meta name="viewport" content="initial-scale=1.0">
   <link rel="stylesheet" href="" />
   <title>オブジェクトの使用</title>
   <style>
table{
   border-collapse:collapse;
}

th,td{
   border:solid 1px black;
}

th{
   background:lavender;
}
   </style>
</head>
<body>
<table>
<caption>2009年時</caption>
<tr>
<th>名前</th><th>期</th><th>出身</th><th>役職</th>
</tr>
<?php
foreach((array)$members as $member){
    print '
<tr>
<td>'.$member->getName().'</td>
<td>'.$member->getGeneration().'</td>
<td>'.$member->getFrom().'</td>
<td>'.$member->getPost().'</td>
</tr>
';
}
?>
</table>
<p>個別の要素を取り出す。</p>
<p>$members[0]の$name:
<?php
print $members[0]->getName();
?>
</p>
<p>役職を書き換える。</p>
<?php
$members[0]->setPost('卒業');
$members[1]->setPost('リーダー');
$members[2]->setPost('卒業');
$members[3]->setPost('サブリーダー');
$members[5]->setPost('卒業');
$members[7]->setPost('卒業');
$members[8]->setPost('卒業');
?>
<table>
<caption>2011年冬</caption>
<tr>
<th>名前</th><th>期</th><th>出身</th><th>役職</th>
</tr>
<?php
foreach((array)$members as $member){
    print '
<tr>
<td>'.$member->getName().'</td>
<td>'.$member->getGeneration().'</td>
<td>'.$member->getFrom().'</td>
<td>'.$member->getPost().'</td>
</tr>
';
}
?>
</table>
</body>
</html>

オブジェクト指向プログラミング

発展

クラスは親子関係を持つなどして、グルーピングすることができる。

キーワード
  • 継承
    • スーパークラス
    • 抽象クラス
  • 実装
    • インタフェース
  • ポリモーフィズム

ここからが「オブジェクト指向」の真髄に入っていくが、本講では扱わない。

オブジェクト指向言語

PHPはオブジェクト指向プログラムとしても書くことはできるが、そうではない書き方(手続き型という)もできる。本講では手続き型の書き方を扱ってきた。

オブジェクト指向プログラミングは一からプログラムを書くというより、組織的に役割分担をしてシステム構築をする際に有効な手法。理解し、慣れるまでは負荷が高い。

オブジェクト指向言語の代表といえばJavaだが、JavaScriptやVisualBasic(VB)という一般ユーザーに普及している言語もオブジェクト指向言語である。それゆえJavaScript,VBともに言語仕様全体を理解するのは非常に難しい。逆に断片的に「つまみ食い」的に扱うのは比較的容易である。