オブジェクトを定義する
オブジェクトを定義すると複雑な処理などをパッケージングできるので、覚えておくと開発の幅が広がっていきます。オブジェクトを定義する際は以下のような点を考慮しながら制作することができます。
- 構造を定義する
- データ型の構造を定義する
- インスタンスを作る
- コンストラクタを設定する
- アクセス修飾子を定義する
- 型宣言を行う
- 新しい値を作る
- クラス・プロパティ設定
- オブジェクト定数を定義
- オブジェクトを利用する
- オブジェクト定数を定義
- クラスを継承する(親クラス・子クラス)
- 抽象クラス(abstract)
- インターフェースの実装
- インターフェースでの型の継承
- 重複する処理をまとめる(トレイト)
- 名前空間
- 例外処理
例えば、以下のようなメンバー登録が必要な機能を実装したいという状況が生じたとする。
//生徒や会員管理などでメンバー登録が必要として配列を用いて登録するとします。
$menbers = [];
$menbers[0] = ['name' => 'takahashi', 'age' => 40 ];
$menbers[1] = ['name' => 'inoue', 'age' => 60 ];
//入力された情報を表示する際の処理を作ったとする
function show($menber)
{
printf('%s (%d)' . PHP_EOL, $menber['name'], $menber['age']);
}
show($menber[0]);
show($menber[1]);
上記の方法でも可能だが、オブジェクトを利用すると管理や拡張性を高めることができるので、開発の際には必須でと言える。大凡の手順と橋は以下の通りだが、具体的に説明してみようと思います。
//1.構造を定義する
class Menber { ... }
//2.新しい値を作る
$menber = new Menber();
//オブジェクトを利用する
$menber->name = 'takahashi';
$menber->age = '40';
$menber->show();
詳しく説明したいと思います。
構造を定義する
実際に定義していきましょう。まずは、オブジェクト(箱)を用意します。その時に「class」を用います。そして、プロパティ(設定)部分に変数やメソッド(処理)を定義してあげます。
データ型の構造を定義する
class Menber{
//プロパティ(設定)
public $name;
public $age;
public $point = 0 ; //初期値を設定したいものは初期化しておく
//メソッド(処理)
public function show(){
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
}
インスタンスを作る
構造を定義するした後に、値を入れる箱を生成します。そのためには、「new」をする必要があります。
$menbers[0] = new Menber(); //インスタンスを生成しました。
$menbers[0]->name = 'takahashi';
$menbers[0]->age = 40;
$menbers[1] = new Menber();//インスタンスを生成しました。
$menbers[1]->name = 'inoue';
$menbers[1]->age = 60;
$menbers[0]->show();
$menbers[1]->show();
コンストラクタを設定する
上でインスタンスを生成したが、以下のように登録することもできる。最初に値を設定することができ便利である。
$menbers[0] = new Menber('takahashi', 40);
<!-- $menbers[0]->name = 'takahashi'; -->
<!-- $menbers[0]->age = 40; -->
$menbers[1] = new Menber('inoue', 60);
<!-- $menbers[1]->name = 'inoue'; -->
<!-- $menbers[1]->age = 60; -->
しかし、そのためにはクラスに'new' した際に渡されるコンストラクタを設定する必要がある。変数を推移を理解するために「FromNew」としているが、慣れてくるとプロパティと同名にすることも多いということを覚えておいてください。
class Menber{
//プロパティ(設定)
public $name;
public $age;
//コンストラクタを設定(FromNewで定義)
//public function __construct($nameFromNew, $ageFromNew){
// $this->name = $nameFromNew;
// $this->age = $ageFromNew;
// }
//コンストラクタを設定(同名で定義)
public function __construct($name, $age){
$this->name = $name;
$this->age = $age;
}
//メソッド(処理)
public function show(){
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
}
アクセス修飾子を定義する
外部からアクセスしてほしくない変数などを定義する時は「private」に設定します。しかし、そうすると外部からのアクセスができず、クラス内で変数を変える処理を作ってあげる必要があります。
class Menber{
//プロパティ(設定)
public $name;
public $age;
private $name;
private $age;
//コンストラクタを設定
public function __construct($name, $age){
$this->name = $name;
$this->age = $age;
}
//メソッド(処理)
public function show(){
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
public function add_age(){
$this->age++;
if($this->age > 120 ){
$this->age = 120;
}
}
}
$menbers[0] = new Menber('takahashi', 40);
<!-- $menbers[0]->name = 'takahashi'; -->
<!-- $menbers[0]->age = 40; -->
$menbers[1] = new Menber('inoue', 60);
<!-- $menbers[1]->name = 'inoue'; -->
<!-- $menbers[1]->age = 60; -->
$Menbers[0]->add_age();
$menbers[0]->show();
$menbers[1]->show();
型を宣言する
変数には色々な値を代入することができますが、それでは困る場合があります。そのような場合には、しっかりと型を宣言してあげる必要があります。
PHPマニュアルで詳細は確認できます。
変数に「string」を宣言するだけでは、PHPでは十分でない場合がある。それで、「declare」を利用して宣言する。
//declareを利用して型をしっかりと確認できる。
declare(strict_types=1);//文字列の宣言
class Menber{
//プロパティ(設定)
// public string $name;
// public int $age;
private string $name; //string型を宣言する
private int $age;
//コンストラクタを設定
public function __construct(string $name, $age){ //ここでも型を宣言をする
$this->name = $name;
$this->age = $age;
}
//メソッド(処理)
public function show(){
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
public function add_age(){
$this->age++;
if($this->age > 120 ){
$this->age = 120;
}
}
}
新しい値を作る
クラス・プロパティ設定
インスタンスに依存しないクラス自体のプロパティを設定することもできる。クラスで行われた処理の回数などを求めることもできる。利用するのは「static」。例えば、先ほども挙げたように会員登録がなされた回数(インスタンスが実施された回数)を求めるときなどに利用できる。
クラスプロパティを設定するが、「static」で定義されているので呼び出し方が独特で「self::」で呼び出す。また、クラス内で利用するので、コンストラクタ内でインスタンス用に変数を定義する必要はない。
class Menber{
private $name;
private $age;
private static $count = 0;//static キーワードを利用してクラス内でプロパティを設定
//コンストラクタを設定
public function __construct($name, $age)//クラス内で利用するものなのでクラス外の「FromNew」が不要
{
$this->name = $name;
$this->age = $age;
self::$count++;//self::で値を呼びコンストラクタが呼ばれるたびにカウントするようにする。
}
//メソッド(処理)
public function show(){
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
public static function showAdd(){
printf('add menber : %d' .PHP_EOL, self::$count); //self::で値を呼ぶこと
}
}
$menbers[0] = new Menber('takahashi', 40);
$menbers[1] = new Menber('inoue', 60);
$menbers[0]->show();
$menbers[1]->show();
Menber::showAdd();
オブジェクト定数を定義
クラス内に定数を定義することもできる。例えば、バージョン情報などを定義する場合。定数であるので、アクセス修飾子を「privete」ではなく「public」にすることもあります。定数は慣習的に大文字にするのと、間違えて「$」を付けないようにしたいですね。
<?php
class Menber{
private $name;
private $age;
private static $count = 0;
public const VERSION = 1.0;//定数の定義
//コンストラクタを設定
public function __construct($name, $age)
{
$this->name = $name;
$this->age = $age;
self::$count++;
}
//メソッド(処理)
public function show(){
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
public static function showAdd()
{
printf('add menber : %d'.PHP_EOL, self::$count);
printf('Version : %.1f'.PHP_EOL, self::VERSION);//定数の処理
}
}
$menbers[0] = new Menber('takahashi', 40);
$menbers[1] = new Menber('inoue', 60);
$menbers[0]->show();
$menbers[1]->show();
Menber::showAdd();
オブジェクトを利用する
クラスを継承する(親クラス・子クラス)
同様の機能を持ったクラスで、拡張機能を実装したい場合などに用いることができる。以下のように子クラスを生成すると親クラスのメソットをそのまま利用することができる。
<?php
class Menber{ //parent class 親クラス
//プロパティ(設定)
protected $name;
protected $age;
public function __construct( $name, $age)
{
$this->name = $name;
$this->age = $age;
}
//メソッド(処理)
public function show()
{
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
}
class VIP_Menber extends Menber{ //sub class 子クラス
private $company;
public function __construct($name, $age, $company)
{
parent::__construct($name, $age) ;
$this->company = $company;
}
public function showVip()
{
printf('Company: %s' .PHP_EOL, $this->company);
}
public function show() //override 上書き
{
printf('%s : Company %s' .PHP_EOL, $this->name, $this->company);
}
}
$menbers[0] = new Menber('takahashi', 40);
$menbers[1] = new Menber('inoue', 60);
$menbers[2] = new VIP_Menber('kimura', 30,'RAKUTEN');
$menbers[0]->show();
$menbers[1]->show();
$menbers[2]->show();
$menbers[2]->showVip();
抽象クラス(abstract)
抽象クラスを用いることで、子クラスに定義されるべき処理などをしてすることができる。開発時に開発忘れを無くすためには必要な定義である。
定義のために「abstract」を用いる。実際の処理は抽象クラスには書かず、親クラスや子クラスで定義する。それで、抽象クラスにはプロパティやコンストラクタを設置すると良い。
<?php
abstract class BaseMenber
{
//プロパティ(設定)
protected $name;
protected $age;
public function __construct( $name, $age)
{
$this->name = $name;
$this->age = $age;
}
abstract public function show();
}
class Menber extends BaseMenber{
//メソッド(処理)
public function show()
{
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
}
class VIP_Menber extends BaseMenber{
private $company;
public function __construct($name, $age,$company)
{
parent::__construct($name, $age) ;
$this->company = $company;
}
public function showVip()
{
printf('Company: %s' .PHP_EOL, $this->company);
}
public function show() //ovwrride 上書き
{
printf('%s : Company %s' .PHP_EOL, $this->name, $this->company);
}
}
$menbers[0] = new Menber('takahashi', 40);
$menbers[1] = new Menber('inoue', 60);
$menbers[2] = new VIP_Menber('kimura', 30,'RAKUTEN');
$menbers[0]->show();
$menbers[1]->show();
$menbers[2]->show();
$menbers[2]->showVip();
インターフェースの実装
抽象クラスを用いると参加のクラスすべてに影響があり、且つ親クラスを複数持つことはできないとの仕様があるので、インターフェースを実装することで、機能を同クラス内の特定のクラスや異なるクラスにも定義することができる。インターフェースには実装(実際に行われる処理)を含めることができない。
「interface」を用い関連付けをするクラスに「implements」で紐づけする。
<?php
interface GoodInterface { //インターフェースを実装する
public function good();
}
abstract class BaseMenber
{
//プロパティ(設定)
protected $name;
protected $age;
public function __construct( $name, $age)
{
$this->name = $name;
$this->age = $age;
}
abstract public function show();
}
class Menber extends BaseMenber
{
//メソッド(処理)
public function show()
{
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
}
class VIP_Menber extends BaseMenber implements GoodInterface //インターフェースを実装
{
private $vip;
private $goods = 0;
public function good(){
$this->goods++;
}
public function __construct($name, $age, $vip)
{
parent::__construct($name, $age) ;
$this->vip = $vip;
}
public function showVip()
{
printf('VIP: %s' .PHP_EOL, $this->vip);
}
public function show() //ovwrride 上書き
{
printf('%s : VIP %s (%d)' .PHP_EOL, $this->name, $this->vip, $this->goods);
}
}
class Company_Menber extends BaseMenber implements GoodInterface //インターフェースを実装
{
private $company;
private $goods = 0;
public function good(){
$this->goods++;
}
public function __construct($name, $age, $company)
{
parent::__construct($name, $age) ;
$this->company = $company;
}
public function showVip()
{
printf('Company: %s' .PHP_EOL, $this->company);
}
public function show() //ovwrride 上書き
{
printf('%s : Company %s (%d)' .PHP_EOL, $this->name, $this->company, $this->goods);
}
}
$menbers[0] = new Menber('takahashi', 40);
$menbers[1] = new Menber('inoue', 60);
$menbers[2] = new VIP_Menber('kimura', 30,'actor');
$menbers[3] = new Company_Menber('Mikitani', 30,'RAKUTEN');
$menbers[4] = new VIP_Menber('tanaka', 50,'comedian');
$menbers[2]->good();
$menbers[3]->good();
function processMember(BaseMenber $member){
$member->show();
}
foreach ($menbers as $menber) {
processMember($menber);
}
インターフェースでの型の継承
インターフェースも型を継承することができます。継承方法は同じ。
//コメントアウトされている処理を継承を用いてみる。
// $menbers[2]->good();
// $menbers[3]->good();
function processGoodInterface(GoodInterface $goodstamp){
$goodstamp->good();
}
processGoodInterface($menbers[2]);
processGoodInterface($menbers[3]);
重複する処理をまとめる(トレイト)
重複する処理がある場合、トレイトを用いると開発時の処理方法を簡素化できる。しかし、トレイトは型の継承はできないのと、癖がある処理でもあるので、利用する際は気をつけてください。
<?php
trait goodmethod {
private $goods = 0;
public function good(){
$this->goods++;
}
}
interface GoodInterface {
public function good();
}
abstract class BaseMenber
{
//プロパティ(設定)
protected $name;
protected $age;
public function __construct( $name, $age)
{
$this->name = $name;
$this->age = $age;
}
abstract public function show();
}
class Menber extends BaseMenber
{
//メソッド(処理)
public function show()
{
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
}
class VIP_Menber extends BaseMenber implements GoodInterface
{
private $vip;
use goodmethod;
public function __construct($name, $age, $vip)
{
parent::__construct($name, $age) ;
$this->vip = $vip;
}
public function showVip()
{
printf('VIP: %s' .PHP_EOL, $this->vip);
}
public function show() //ovwrride 上書き
{
printf('%s : VIP %s (%d)' .PHP_EOL, $this->name, $this->vip, $this->goods);
}
}
class Company_Menber extends BaseMenber implements GoodInterface
{
private $company;
use goodmethod;
public function __construct($name, $age, $company)
{
parent::__construct($name, $age) ;
$this->company = $company;
}
public function showVip()
{
printf('Company: %s' .PHP_EOL, $this->company);
}
public function show() //ovwrride 上書き
{
printf('%s : Company %s (%d)' .PHP_EOL, $this->name, $this->company, $this->goods);
}
}
$menbers[0] = new Menber('takahashi', 40);
$menbers[1] = new Menber('inoue', 60);
$menbers[2] = new VIP_Menber('kimura', 30,'actor');
$menbers[3] = new Company_Menber('Mikitani', 30,'RAKUTEN');
$menbers[4] = new VIP_Menber('tanaka', 50,'comedian');
// $menbers[2]->good();
// $menbers[3]->good();
function processGoodInterface(GoodInterface $goodstamp){
$goodstamp->good();
}
processGoodInterface($menbers[2]);
processGoodInterface($menbers[3]);
function processMember(BaseMenber $member){
$member->show();
}
foreach ($menbers as $menber) {
processMember($menber);
}
外部ファイルを読み込む
以下の記述を行って外部のファイルを読み込みます。
- require …読み込まれない場合、処理が止まる
- include …読み込まれない場合でも、処理は止まらない
- require_once …一度読み込まれていると2度は読み込まれない。
- include_once …一度読み込まれていると2度は読み込まれない。
- spl_autoload_register …同ファイル内で処理されたクラスを取得することができる。
<?php
trait goodmethod {
private $goods = 0;
public function good(){
$this->goods++;
}
}
interface GoodInterface {
public function good();
}
abstract class BaseMenber
{
//プロパティ(設定)
protected $name;
protected $age;
public function __construct( $name, $age)
{
$this->name = $name;
$this->age = $age;
}
abstract public function show();
}
class Menber extends BaseMenber
{
//メソッド(処理)
public function show()
{
printf('%s (%d)' .PHP_EOL, $this->name, $this->age);
}
}
class VIP_Menber extends BaseMenber implements GoodInterface
{
private $vip;
use goodmethod;
public function __construct($name, $age, $vip)
{
parent::__construct($name, $age) ;
$this->vip = $vip;
}
public function showVip()
{
printf('VIP: %s' .PHP_EOL, $this->vip);
}
public function show() //ovwrride 上書き
{
printf('%s : VIP %s (%d)' .PHP_EOL, $this->name, $this->vip, $this->goods);
}
}
class Company_Menber extends BaseMenber implements GoodInterface
{
private $company;
use goodmethod;
public function __construct($name, $age, $company)
{
parent::__construct($name, $age) ;
$this->company = $company;
}
public function showVip()
{
printf('Company: %s' .PHP_EOL, $this->company);
}
public function show() //ovwrride 上書き
{
printf('%s : Company %s (%d)' .PHP_EOL, $this->name, $this->company, $this->goods);
}
}
<?php
require_once('Menber.php'); //処理が止ってエラー表示がある
spl_autoload_register(function($class){ //「new Menber」を利用していないと「$class」が取得できない
require($class.'.php');
});
$menbers[0] = new Menber('takahashi', 40);
$menbers[1] = new Menber('inoue', 60);
$menbers[2] = new VIP_Menber('kimura', 30,'actor');
$menbers[3] = new Company_Menber('Mikitani', 30,'RAKUTEN');
$menbers[4] = new VIP_Menber('tanaka', 50,'comedian');
// $menbers[2]->good();
// $menbers[3]->good();
function processGoodInterface(GoodInterface $goodstamp){
$goodstamp->good();
}
processGoodInterface($menbers[2]);
processGoodInterface($menbers[3]);
function processMember(BaseMenber $member){
$member->show();
}
foreach ($menbers as $menber) {
processMember($menber);
}
名前空間
名前空間を利用して同クラスの定義がなされないようにする。
例えば、「Menber.php」内にMemberクラスがあるが、開発中に「index.php」にMemberクラスを記述するとエラーが起きる。そのような状況を避けるために「namespace」を定義する。
定義する際に「ベンダー名(販売者名)\ プロジェクト名」と記載することが多い。定義されたクラスに「namespace」を関連付けするのを忘れないように。
<?php
namespace Sonsanweb\ProjectApp;
<?php
//use Sonsanweb\ProjectApp as ProjectApp;
use Sonsanweb\ProjectApp; //as 以降の定義名が一緒の場合は省略可
spl_autoload_register(function($class){
require($class.'.php');
});
//以降の定義されたクラスに「namespace」を関連付けする
$menbers[0] = new ProjectApp\Menber('takahashi', 40);
$menbers[1] = new ProjectApp\Menber('inoue', 60);
$menbers[2] = new ProjectApp\VIP_Menber('kimura', 30,'actor');
$menbers[3] = new ProjectApp\Company_Menber('Mikitani', 30,'RAKUTEN');
$menbers[4] = new ProjectApp\VIP_Menber('tanaka', 50,'comedian');
function processGoodInterface(ProjectApp\GoodInterface $goodstamp){
$goodstamp->good();
}
processGoodInterface($menbers[2]);
processGoodInterface($menbers[3]);
function processMember(ProjectApp\BaseMenber $member){
$member->show();
}
foreach ($menbers as $menber) {
processMember($menber);
}
例外処理
処理の中に例外処理を施し、処理が止まるようにする。例えば、年齢が18歳以下は登録できないようにするとします。
<?php
abstract class BaseMenber
{
//プロパティ(設定)
protected $name;
protected $age;
public function __construct( $name, $age)
{
if($age < 18){
throw new Exception('Your age so young!');
}
$this->name = $name;
$this->age = $age;
}
abstract public function show();
}
<?php
use Sonsanweb\ProjectApp;
spl_autoload_register(function($class){
require($class.'.php');
});
// require('Menber.php'); //処理が止ってエラー表示がある
// include('Menber.php'); //処理が止らない
$menbers[0] = new ProjectApp\Menber('takahashi', 10);//年齢が18以下を登録
$menbers[1] = new ProjectApp\Menber('inoue', 60);
$menbers[2] = new ProjectApp\VIP_Menber('kimura', 30,'actor');
$menbers[3] = new ProjectApp\Company_Menber('Mikitani', 30,'RAKUTEN');
$menbers[4] = new ProjectApp\VIP_Menber('tanaka', 50,'comedian');
// $menbers[2]->good();
// $menbers[3]->good();
try {
function processGoodInterface(ProjectApp\GoodInterface $goodstamp){
$goodstamp->good();
}
processGoodInterface($menbers[2]);
processGoodInterface($menbers[3]);
function processMember(ProjectApp\BaseMenber $member){
$member->show();
}
foreach ($menbers as $menber) {
processMember($menber);
}
} catch (Exception $e) {
//throw $th;
echo $e->getMessage().PHP_EOL;
}