このレッスンはただ今 無料公開中 です。

初学者向け マンツーマン プログラミング・レッスン

PHPのクラス

この章からはいよいよPHPの「クラス」について学んでいきます。これまでの内容の集大成とも言えます。「難しいな」と感じたら、必要に応じて以前までの章を復習するようにしましょう。

クラスとは

変数は、値(データ) に名前をつけて保存しておき、いつでも使い回せるようにしたものでした。また関数は、処理(ふるまい) に名前をつけて定義しておき、いつでも呼び出して使えるようにしたものでした。

それでは「クラス」はというと、処理 をひとまとまりにして役割を与え、それに名前をつけて定義したものと言うことができるでしょう。

つまりクラスはそれ自身の中に「変数」と「関数」を持つことが出来るのです。

クラスの定義

概念的な話をしていてもイメージが沸かないと思いますので、簡単なクラスのサンプルコードを見てみましょう。

class_human
<?php
  class Human
  {
    public $name = '';
    public $weight = 0;

    public function eat() {
      $this->weight += 1;
    }
    public function run() {
      $this->weight -= 1;
    }
  }

Humanという名前のクラスを定義してみました。public という見慣れないキーワードこそついていますが、このクラスの中には見慣れた $name や $weight といった変数があります。また、これも見慣れた function というキーワードに続いて eat() や run() という関数が定義されています。(publicは「アクセス修飾子」といいます。詳しくはこれ以降の章で学びます。)

このHumanクラスはこれらの変数や関数をつかって、ある役割を果たすことになります。

なんとなくイメージが沸くと思いますが、このクラスは eat() 関数を呼び出すと体重が 1 増え、また、run() 関数を呼び出すと体重が 1 減るように設計されています。

クラスの書き方

<?php
  class クラス名
  {
    変数1
    変数2
    ...

    function 関数1() {

    }

    function 関数2() {

    }
    ...
  }

関数のときにも学びましたが、関数は定義しただけでは何も行われなかったですよね。関数を呼び出して初めて、中に書かれた内容が実行されたのでした。

クラスでも似たようなことが言えます。上記のように書かれたクラスはあくまでも「定義」であって、決まりごとが決められたものに過ぎません。どこかでこのクラスを使ってあげる必要がありますね。

関数を使うのよりも実はもう少し複雑な事情があって、それには「インスタンス」という言葉を覚え、またそのイメージを持てるようになる必要があります。

ここはかなり重要な箇所なので、右脳を働かせてしっかりとイメージを描きつつ、左脳も働かせて論理的に理解して下さい。

インスタンスとは

クラスとは「定義」に過ぎませんでした。言ってみれば「設計図」や「金型」のようなものです。
クラスを呼びだして使うというのは、この設計図から物体を生み出すことに似ています。

先ほどのHumanクラスをここでもう一度見てみましょう。

class_human
<?php
  class Human
  {
    public $name = '';
    public $weight = 0;

    public function eat() {
      $this->weight += 1;
    }
    public function run() {
      $this->weight -= 1;
    }
  }

これはHumanという設計図です。この設計図から実体となるHumanを生み出すと、その実体は $name や $weight といったデータを持つことができ、また、eat() や run() という動作を行うことができるようになります。
そのように設計されているのです。

それではこの設計図から、実際の人間を生み出してみましょう。

class_human
<?php
  class Human
  {
    public $name = '';
    public $weight = 0;

    public function eat() {
      $this->weight += 1;
    }
    public function run() {
      $this->weight -= 1;
    }
  }

  $tanaka = new Human();
  $tanaka->name = '田中';
  $tanaka->weight = 69;
  $tanaka->run();
  print $tanaka->name. 'さんの体重は'. $tanaka->weight. 'kgです。'. PHP_EOL;

これを実行すると

田中さんの体重は68kgです。

となりました。何となく次のようなイメージを持つことができたでしょうか?

Humanクラスから実体を生み出し、$tanaka という変数に代入した
$tanaka に「田中」という名前(name)データをセットした
$tanaka に「69」という体重(weight)データをセットした
$tanaka に run() という動作を実行させた
その結果、体重が 1 減った
最後に名前と現在の体重「68」kgを出力した。

インスタンス化

クラスから実体を生み出すには new キーワードを使います。

$tanaka = new Human();

設計図であるHumanクラスには、人間としての名前や体重などというデータはありませんでしたが、そこから生成した実体である $tanaka には「田中」という名前をつけ、「69」という体重を与えることができました。

$tanaka->name = '田中';
$tanaka->weight = 69;

このように設計図から実体を生み出すことを「インスタンス化」といいます。また、生み出された実体のことを「インスタンス」と呼びます。

一度クラスを定義しておけば、インスタンスはいくらでも生成できます。今回は田中さんをインスタンス化しましたが、それとは別に、鈴木さんや佐藤さんのインスタンスだって生み出すことができるのです。

このような クラスインスタンス の関係を、よく覚えておいて下さい。設計図から実体が生み出されるイメージが描けると尚良いです。鯛焼きの金型に材料を流し込んで焼けば、いくらでも鯛焼きが作れる、そんなイメージです。

プロパティとメソッド

ところで、クラスに定義した変数や関数には、別の呼び方があります。変数のことを「プロパティ」と呼び、関数は「メソッド」と呼びます。機能的には似たようなものですが、クラスの中で使うことで、より高性能になっています。詳しくはあとで述べますが、これらの呼び方も覚えておいて下さい。

尚、インタンスに備わったプロパティやメソッドのことを、それぞれ「インスタンスプロパティ」「インスタンスメソッド」といいます。

アロー演算子

インスタンスのプロパティやメソッドにアクセスするには、 -> という記号を使います。これは「アロー演算子」といいます。

$tanaka->name = '田中';
$tanaka->weight = 69;
$tanaka->run();

プロパティは変数と同じように代入したり、あとからその値を使い回すことができます。

メソッドについても同様で、関数のように何度も呼び出して使うことができます。今回のサンプルコードには登場していませんが、引数ももちろん使えます。

$this とはなんだ?

ここでサンプルコードをもう一度確認しておきましょう。まだ説明していない部分もありますし、もっと発展的な使い方もあとでご紹介していきます。

class_human
<?php
  class Human
  {
    public $name = '';
    public $weight = 0;

    public function eat() {
      $this->weight += 1;
    }
    public function run() {
      $this->weight -= 1;
    }
  }

  $tanaka = new Human();
  $tanaka->name = '田中';
  $tanaka->weight = 69;
  $tanaka->run();
  print $tanaka->name. 'さんの体重は'. $tanaka->weight. 'kgです。'. PHP_EOL;

アクセス修飾子「public」はもう少しあとで触れるとして、もう1つ見慣れないキーワードがあります。それが $this です。

$thisは インスタンス自身 を表します。

$tanaka = new Human();

ここで Human クラスをインスタンス化しました。この時点で、$tanaka には $name や $weight というプロパティと、 eat() や run() というメソッドが備わります。$tanaka はこれ以降、そういった機能を持っている「オブジェクト」として振る舞うことができるようになりました。しかしながら、まだ生まれたばかりで何のデータも持っていません。

$tanaka->name = '田中';

ここでようやく「名前」を持つことができました。続いて、

$tanaka->weight = 69;

体重もセットされました。重みが増して、より実体としてイメージしやすくなったでしょうか。

さて、いよいよ次です。

$tanaka->run();

田中さんが走りました。走るとカロリーを消費して体重を 1 減らす事ができます。そのような取り決めをしているのが run() メソッドです。

public function run() {
  $this->weight -= 1;
}

$thisが登場しました。田中さんが走ったので、田中さんの体重が 1 減ります。 $this が「田中さん本人」であることがイメージできたでしょうか。もしもこの他に「鈴木さん」や「佐藤さん」のインスタンスが生まれていたとしても、 $tanaka->run() で体重が減るのは田中さん本人だけです。鈴木さんや佐藤さんの体重が減るわけではありません。

このように、$this とはインスタンス自身を表します。クラスの定義は単なる設計図なので、誰に呼ばれるかはわかりません。今後いくつも生成されるであろうインスタンスたちに対して「呼んでくれたら、その人の体重を 1 減らすよ」という取り決めをしています。ただ、設計段階ではそれが誰かはわからないので、クラス定義の中では $this と書いておきます。そして、その時アクセスしてきたインスタンス自身に対してのみ、処理を実行できるようになっているのです。

コンストラクタについて

クラスのもうひとつ便利な機能を紹介します。Humanクラスは次のように書くことで、もっとシンプルで見通しが良くなります。

class_human.php
<?php
  class Human
  {
    public $name = '';
    public $weight = 0;

    public function __construct($name, $weight) {
      $this->name = $name;
      $this->weight = $weight;
    }

    public function eat() {
      $this->weight += 1;
    }
    public function run() {
      $this->weight -= 1;
    }
  }

  $tanaka = new Human('田中', 69);
  $tanaka->run();
  print $tanaka->name. 'さんの体重は'. $tanaka->weight. 'kgです。'. PHP_EOL;

新たに登場したのが「コンストラクタ」です。

public function __construct($name, $weight) {
  $this->name = $name;
  $this->weight = $weight;
}

コンストラクタ __construct() は特殊メソッドで、インスタンスが生成される時に1番最初に必ず実行されます。用途はいろいろありますが、主にプロパティの初期化をするのによく使われます。

$tanaka = new Human('田中', 69);

コンストラクタはあくまでもメソッドなので、引数を受け取ることができます。 第1引数の $name には「田中」が、そして第2引数の $weight には「69」が、それぞれ渡されてきています。
コンストラクタのブロック内部では、この引数を自身のプロパティとしてセットする記述があります。

$this->name = $name; // nameプロパティに第1引数 $name('田中')を代入
$this->weight = $weight; // weightプロパティに第2引数 $weight(69)を代入

このようなコンストラクタの使い方も覚えておくと良いでしょう。今回はプロパティの初期化に使用しましたが、用途はさまざまです。

静的プロパティと静的メソッド(static)

PHPでは、クラスに「静的なプロパティ」や「静的なメソッド」を定義しておくこともできます。
今まで扱ってきたのはその反対の「動的な」プロパティやメソッドでした。インスタンスが生成されるたびに、インスタンス自身にそれらの機能が動的に備わりました。田中さんが走れば、田中さんの体重が減りますし、鈴木さんが食べれば、鈴木さんの体重が増えます。

では静的なプロパティやメソッドとは、どのようなものでしょうか。
わかりやすいように別の新しいクラスを作って説明します。商品と値段に関する簡単なサンプルです。

注)2019.07執筆時点で、消費税率は 8% です。
class_product.php
<?php
  class Product
  {
    public $produce_name = '';
    public $price = 0;
    public static $tax = 0.08;

    public function __construct($product_name, $price) {
      $this->product_name = $product_name;
      $this->price = $price;
    }
    public function show() {
      $price = $this->price + $this->price * self::$tax;
      print $this->product_name. 'は税込み'. $price. '円です。';
    }

    public static function show_tax() {
      print '消費税は'.  self::$tax * 100 . '%です';
    }
  }

  $pencil = new Product('鉛筆', 80);
  $apple = new Product('りんご', 100);

  $pencil->show();
  $apple->show();

  Product::show_tax();

概要を説明すると、このクラスは「商品」を設計していて、$product_name(品名)と $price(値段)というデータをインスタンスに持たせることができます。また、show()メソッドを実行するとそのインスタンスの品名と値段を「消費税込み」で表示するようになっています。

public static $tax = 0.08;

ここで static キーワードが出てきました。これがつくことで、このプロパティは「静的」なものになります。これはどういうことかというと、インスタンス自身が持っているデータではなく、クラス自体がそれを保持している、ということが言えます。つまり、インスタンスを生成しなくてもそのデータにアクセスできるのです。

値段は商品ごとに異なるのは当然のことですよね。ですが、消費税率はどうでしょうか。鉛筆だろうとりんごだろうと、その率は「8%」です。(2019/07執筆時点)

このように、インスタンスに依存しないデータはクラス自身が持っていた方が都合が良いです。インスタンス変数としてもたせるべきではありません。
メソッドにも同様のことが言えます。「消費税率を表示する」という命令は、インスタンスが持っている必要はなく、クラス側で一括管理するべきです。

staticの使い方

staticなプロパティやメソッドにアクセスするには、アロー演算子を使いません。変わりに :: ダブルコロンを使用します。

クラス名::$staticプロパティ
クラス名::staticメソッド()

サンプルコードの一番最後の行で、消費税率を表示させるメソッドを呼び出しているところがそうです。

Product::show_tax();

また、前項で $this について学びましたが、$this は「インスタンス自身」をクラス定義内で表すキーワードでした。
一方、クラス自身を表すキーワードは self になります。

クラス定義内でstaticなプロパティやメソッドにアクセスするには次のように書きます。

self::$tax

$this ではなく self になりました。 $self ではないこと、またプロパティには $tax というように $ がつくことに注意して下さい。インスタンスプロパティへのアクセス方法と微妙に異なる点です。

$this->weight // インスタンス変数
self::$tax // static変数

この書き分けは、理屈ではなく覚えてしまった方が早いでしょう。

まとめ

いかがでしたか?
かなりボリュームのある内容となりました。クラスとはそれだけ高機能なものであるとも言えます。

しかしながら実は、この章で述べたことはクラスのまだほんの一部に過ぎません。ここから先の章ではいよいよ、オブジェクト指向プログラミングについて学んでいきます。

  • クラスの継承
  • ポリモーフィズム
  • カプセル化

これらの機能を使うことで、クラスはより高度で便利なものになっていきます。

ただ、難しそうだからといってあまり身構えたり、考え込まないようにして下さい。リラックスして、イメージで捉えていくことも大切です。そして、一度で理解しきれな部分は一旦流して、時間をおいてあとから復習をすることも効果的です。

オブジェクト指向の学習に入る前に、本章で学んだことの理解度チェックをしましょう。次の練習問題を行なってみて下さい。

練習問題

「車」を表現するクラスを作ってみましょう。クラス名は「Car」として、次のプロパティとメソッドをもたせて下さい。なお、アクセス修飾子はすべて public としてください。

プロパティ

  • 車種:$model
  • 時速:$speed
  • 走行距離:$distance

メソッド

  • コンストラクタ:__counstruct()
  • 走行する:run()

Carクラスの仕様

  • コンストラクタで「車種」と「時速」を初期化して下さい。
  • run()メソッドの引数には「走行時間」を渡して下さい。
  • run()メソッドでは、時速と走行時間から「走行距離」を計算して $distance に代入して下さい。

Carクラスの呼び出し

  • 予め指定された4つの車種からランダムで1つが選ばれます。
  • 時速は70km/h〜120km/hの範囲内でランダムに指定されます。
  • 走行時間は1〜5時間の範囲内でランダムに指定されます。
  • 車種と時速をコンストラクタに渡してCarクラスからインスタンスを生成して下さい。
  • 走行時間を引数としてインスタンスメソッド run() を呼び出して下さい。
  • 最終的に次のような文章が出力されるようにして下さい。
(?:車種名)は時速(?)km/hで(?)時間走行し(?)km移動しました。
class_car.php
<?php
class Car
{
  // TODO: Carクラスを定義して下さい
}

$models = ["ベンツ", "ポルシェ", "レクサス", "プリウス"];

$model = $models[rand(0, 3)];
$speed = rand(70, 120);
$hour = rand(1, 5);

// TODO: Carクラスのインスタンスを生成して下さい

// TODO: Carインスタンスを $hour 時間分走行させて下さい

// TODO: 書式に合うように情報を出力して下さい。