PHPのクラス

PHPには、オブジェクト指向プログラミングのための機能が用意されています。クラスを利用することにより、効率的なプログラミング、メンテナンス性の向上、別プロジェクトにおけるプログラムの再利用といった多くの恩恵を受けることができます。

クラス定義とインスタンス生成

クラスは、classキーワードを使って定義します。クラス名はPHPの識別子のルールに従う必要があります。また、名前空間を使わない場合、クラスはグローバルに定義されるので定義済みのクラス名を使うことはできません。

下記の例では、プロパティやメソッドを何も持たないFooクラスを定義しています。クラスのインスタンスを生成するには、new演算子を使用します。結果として、変数$fooにFooクラスのインスタンスの参照が代入されます。

PHP

<?php
class Foo
{
}
$foo = new Foo();
var_dump($foo); // 出力:object(Foo)#1 (0) { }
?>

プロパティ

クラスに定義する変数をプロパティといいます。プロパティは、クラス定義内でアクセス修飾子の後に$記号と識別子を記述して宣言します。宣言と同時に必要に応じて初期化することもできます。プロパティにアクセスするには、アロー演算子"->"を使用します。

また、プロパティは動的に生成することも可能です。下記の例では、クラス定義時に宣言していないfoo_boolというプロパティを使用していますが、エラーになりません。しかし、第3者が見ると非常にわかりにくいので、使用するプロパティは予め宣言しておくべきでしょう。

PHP

<?php
class Foo
{
  public $foo_str = 'class Foo';
  public $foo_int;
}
$foo = new Foo();
echo $foo->foo_str, PHP_EOL; // 出力:class Foo
$foo->foo_int = 1;
echo $foo->foo_int, PHP_EOL; // 出力:1
$foo->foo_bool = true;
var_dump($foo->foo_bool); // 出力:bool(true)
?>

メソッド

クラスに定義する関数をメソッドといいます。メソッドは、クラス定義内で関数定義と同じようにfunctionキーワードで定義します。メソッドは、アロー演算子でアクセスし呼び出すことができます。

メソッド内では、インスタンス自身の参照を持った$thisという疑似変数を使用することができます。$thisを通して、自身に定義されたプロパティやメソッドにアクセスできます。また、メソッドの戻り値を参照で返したい場合は、関数と同じようにメソッド名の先頭に&を付けて宣言します。

PHP

<?php
class Foo
{
  public $name = 'Foo';
  public function echoLabel()
  {
    echo '$name:';
  }
  public function echoName()
  {
    $this->echoLabel();
    echo $this->name, PHP_EOL;
  }
  public function &getInstance()
  {
    return $this;
  }
}
$foo = new Foo();
$foo->echoName(); // 出力:$name:Foo
$hoge =& $foo->getInstance();
$hoge->name = 'Hoge';
$foo->echoName(); // 出力:$name:Hoge
?>

アクセス修飾子

プロパティやメソッドは、アクセス修飾子によってアクセス権を設定することができます。PHPでは、public, private, protectedをアクセス修飾子として指定できます。

public
publicが指定されたプロパティやメソッドは、クラスの外側からもアクセスすることができます。プロパティをvarを使って宣言した場合やメソッド定義時にアクセス修飾子を省略した場合は、publicが指定されたものとして扱われます。
private
privateが指定されたプロパティやメソッドは、クラスの内側からのみアクセスすることができます。
protected
protectedが指定されたプロパティやメソッドは、クラスの内側や自身のクラスを継承したクラスからのみアクセスすることができます。

PHP

<?php
class Foo
{
  private $private = 'private';
  protected $protected = 'protected';
  public $public = 'public';
  public function fooFunc()
  {
    echo $this->private, PHP_EOL; // 出力:private
    echo $this->protected, PHP_EOL; // 出力:protected
    echo $this->public, PHP_EOL; // 出力:public
  }
}
class FooChild extends Foo
{
  public function fooChildFunc()
  {  
    echo $this->private, PHP_EOL; // 出力:Notice: Undefined property
    echo $this->protected, PHP_EOL; // 出力:protected
    echo $this->public, PHP_EOL; // 出力:public
  }
}
$foo = new Foo();
/* 実行するとFatal error
echo $foo->private, PHP_EOL; // 出力:Fatal error: Cannot access private property
echo $foo->protected, PHP_EOL; // 出力:Fatal error: Cannot access protected property
*/
echo $foo->public, PHP_EOL; // 出力:public
$foo->fooFunc();
$fooChild = new FooChild();
$fooChild->fooChildFunc();
?>

staticプロパティ・staticメソッド

プロパティやメソッドをstaticキーワードを付けて定義すると、インスタンス化することなく、クラスを通してアクセスすることができます。staticプロパティは静的プロパティ、staticメソッドは静的メソッドとも呼ばれます。

staticプロパティやstaticメソッドにアクセスするには、クラス名にスコープ定義演算子"::"を付けてアクセスします。クラス内部からアクセスする場合は、selfキーワードにスコープ定義演算子"::"を付けてアクセスすることもできます。

PHP

<?php
class Foo
{
  public static $name = 'Foo';
  public static function echoLabel()
  {
    echo 'static $name:';
  }
  public static function echoName()
  {
    self::echoLabel();
    echo self::$name, PHP_EOL;
  }
  public function getName()
  {
    return self::$name;
  }
  public function setName($value)
  {
    Foo::$name = $value;
  }
}
echo Foo::$name, PHP_EOL; // 出力:Foo
Foo::echoName(); // 出力:static $name:Foo
$foo = new Foo();
$foo2 = new Foo();
$foo2->setName('Foo2');
echo $foo->getName(), PHP_EOL; // 出力:Foo2
?>

クラス定数

定数とは、変更できない値を保持するものです。クラス内に定義する定数をクラス定数といいます。クラス定数を定義するには、constキーワードを使用します。変数と違って識別子の先頭に$記号は必要ありません。

クラス定数には、クラス名にスコープ定義演算子"::"を付けてアクセスできます。クラス内部からは、selfキーワードにスコープ定義演算子"::"を付けてアクセスすることもできます。

PHP

<?php
class Foo
{
  const constant = 'const';
  public static function echoConst()
  {
    echo self::constant, PHP_EOL;
  }
  public function getConst()
  {
    return Foo::constant;
  }
}
echo Foo::constant, PHP_EOL; // 出力:const
Foo::echoConst(); // 出力:const
$foo = new Foo();
echo $foo->getConst(), PHP_EOL; // 出力:const
?>

コンストラクタとデストラクタ

コンストラクタ

コンストラクタとは、クラスがインスタンス化される際に自動的に呼ばれるメソッドです。多くの場合、コンストラクタで初期化に必要な処理などを行いますが、必要なければ省略することもできます。PHPでは、__constructという名前のメソッドが、コンストラクタとして実行されます。

デストラクタ

デストラクタは、インスタンスが破棄される際に自動的に呼ばれるメソッドです。リソースの解放などの処理を行う必要がある場合にデストラクタで処理しますが、必要なければ省略可能です。PHPでは、__destructという名前のメソッドが、デストラクタとして実行されます。

下記の例では、$fooにNULLを代入した時点でインスタンスのリファレンスカウントが0になり、デストラクタが実行されます。参照を明示的に破棄しなかった場合は、PHPプログラムの実行終了時に順不同でデストラクタが呼ばれます。これは、PHPプログラムの最後の行の後、つまりHTMLを出力している場合は、</html>の後であることには注意が必要です。

PHP

<?php
class Foo
{
  private $name;
  public function __construct($name)
  {
    $this->name = $name;
    echo $this->name . "'s __construct() is called.", PHP_EOL;
  }
  public function __destruct()
  {
    echo $this->name . "'s __destruct() is called.", PHP_EOL;
    unset($this->name);
  }
}
$foo = new Foo('Foo'); // 出力:Foo's __construct() is called.
$foo = NULL; // 出力:Foo's __destruct() is called.
?>

インスタンスの参照と複製

クラスのインスタンスを代入した変数は、常に参照として扱われます。そのため、例えば関数の引数に渡す際は参照渡しをしなくても参照が渡されます。また、インスタンスの参照を持った変数を別の変数に代入した場合は、インスタンスへの参照情報がコピーされるため、2つの変数は同じインスタンスを指し示す変数となります。

インスタンスを複製するには、cloneキーワードを使用します。下記の例では、$fooを代入した$hogeは、$fooと同じインスタンスの参照であることがわかります。一方、cloneで$fooを複製した$barは、複製された別のインスタンスであることが確認できます。

PHP

<?php
class Foo
{
  public $num = 1;
}
function decuple($arg)
{
  $arg->num *= 10;
}
$foo = new Foo();
decuple($foo);
echo $foo->num, PHP_EOL; // 出力:10
$hoge = $foo;
var_dump($foo === $hoge); // 出力:bool(true)
decuple($hoge);
echo $foo->num, PHP_EOL; // 出力:100
$bar = clone $foo;
var_dump($foo === $bar); // 出力:bool(false)
decuple($bar);
echo $foo->num, PHP_EOL; // 出力:100
echo $bar->num, PHP_EOL; // 出力:1000
?>

オブジェクトの比較

オブジェクト同士の比較において、通常の比較演算子"=="を使用した場合は、同じクラスのインスタンスであり、プロパティの値が等しい場合にTRUEとなります。また、厳密な比較演算子"==="を使用した場合は、同じインスタンスの参照である場合のみTRUEとなります。

PHP

<?php
class Foo
{
  public $name;
  public function __construct($name)
  {
    $this->name = $name;
  }
}
$foo = new Foo('Foo');
$hoge = new Foo('Hoge');
$bar = $foo;
$baz = clone $foo;
var_dump($foo == $hoge); // 出力:bool(false)
var_dump($foo == $bar); // 出力:bool(true)
var_dump($foo === $bar); // 出力:bool(true)
var_dump($foo == $baz); // 出力:bool(true)
var_dump($foo === $baz); // 出力:bool(false)
?>