各クラスの定義は、classキーワードで始まり、クラス名が続きます。 そしてその後に波括弧のペアが続き、 その中にはクラスのプロパティとメソッドの定義を記述します。
クラス名には、PHP の予約語 以外でラベルとして有効なあらゆる名前を使用することができます。 有効なクラス名は、先頭が文字あるいはアンダースコアで始まり、 その後に任意の数の文字/数字/アンダースコアが続くものです。 正規表現で表すと、 ^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$ のようになります。
クラスの中には、 定数 や 変数 ("プロパティ" といいます) そして関数 ("メソッド" といいます) を含めることができます。
例1 簡単なクラス定義
<?php
class SimpleClass
{
// プロパティの宣言
public $var = 'a default value';
// メソッドの宣言
public function displayVar() {
echo $this->var;
}
}
?>
メソッドがオブジェクトコンテキストからコールされる場合は、 疑似変数 $this が利用可能です。 $this は、呼び出し元オブジェクト (通常は、メソッドが属するオブジェクトですが、 メソッドが第二のオブジェクトのオブジェクトの コンテキストから スタティックに コールされる場合には、別のオブジェクトとなる場合もあります) への参照です。 PHP 7.0.0 以降は、スタティックではないメソッドを非互換のコンテキストでスタティックに呼び出すと、 そのメソッド内では $this が未定義の状態になります。 スタティックではないメソッドの、非互換なコンテキストにおけるスタティック呼び出しは PHP 5.6.0 で非推奨になりました。 PHP 7.0.0 ではさらに、コンテキストの互換・非互換にかかわらず、 スタティックではないメソッドのスタティック呼び出し全般が非推奨となりました。 PHP 5.6.0 より前のバージョンでも、これらは既に strict 通知が出ていたものです。
例2 $this 疑似変数の例
この例は、error_reporting が無効になっていることを前提としています。 これが有効になっている場合、PHP のバージョンによって deprecated や strict の通知が出るでしょう。
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this is not defined.\n";
}
}
}
class B
{
function bar()
{
A::foo();
}
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
上の例の PHP 5 での出力は、このようになります。
$this is defined (A) $this is not defined. $this is defined (B) $this is not defined.
上の例の PHP 7 での出力は、このようになります。
$this is defined (A) $this is not defined. $this is not defined. $this is not defined.
あるクラスのインスタンスを生成するには、new キーワードを使わなければなりません。エラー時に 例外をスローするような コンストラクタを定義していない限り、 オブジェクトが常に生成されます。 クラスは、そのインスタンスを作成する前に定義しなければなりません (これが必須となる場合もあります)。
クラス名を含む文字列を new で指定すると、 そのクラスのインスタンスを作成します。クラスが名前空間に属している場合は、 完全修飾名を指定しなければなりません。
例3 インスタンスを作成する
<?php
$instance = new SimpleClass();
// 変数を使うこともできます
$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
?>
クラスのコンテキストにおいては、 new self や new parent のようにして新しいオブジェクトを作成することができます。
作成済みのクラスのインスタンスを新たな変数に代入する場合、新しい変数は、 代入されたオブジェクトと同じインスタンスにアクセスします。 この動作は、インスタンスを関数に渡す場合も同様です。 作成済みのオブジェクトのコピーは、その クローンを作成 することにより作成可能です。
例4 オブジェクトの代入
<?php
$instance = new SimpleClass();
$assigned = $instance;
$reference =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance と $reference は null になります
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
上の例の出力は以下となります。
NULL NULL object(SimpleClass)#1 (1) { ["var"]=> string(30) "$assigned will have this value" }
PHP 5.3.0 以降では、オブジェクトのインスタンスを作成する別の方法が新たに導入されました。
例5 新しいオブジェクトの作成
<?php
class Test
{
static public function getNew()
{
return new static;
}
}
class Child extends Test
{}
$obj1 = new Test();
$obj2 = new $obj1;
var_dump($obj1 !== $obj2);
$obj3 = Test::getNew();
var_dump($obj3 instanceof Test);
$obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
?>
上の例の出力は以下となります。
bool(true) bool(true) bool(true)
PHP 5.4.0 以降では、新しく作成したオブジェクトのメンバーに、作成したその式の中でもアクセスできるようになりました。
例6 新しく作成したオブジェクトのメンバーへのアクセス
<?php
echo (new DateTime())->format('Y');
?>
上の例の出力は、 たとえば以下のようになります。
2016
クラスのプロパティとメソッドは、それぞれ別の "名前空間" に存在するので、 同じ名前のプロパティとメソッドを共存させることもできます。 プロパティを参照する場合もメソッドを参照する場合も書きかたは同じです。 それがプロパティへのアクセスなのかメソッドの呼び出しなのかは、そのコンテキストによって決まります。 つまり、変数にアクセスしようとしているのか関数を呼び出そうとしているのかの違いです。
例7 プロパティへのアクセスとメソッドの呼び出し
class Foo
{
public $bar = 'property';
public function bar() {
return 'method';
}
}
$obj = new Foo();
echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;
上の例の出力は以下となります。
property method
これはつまり、プロパティに 無名関数 を代入した場合に、その関数は直接呼び出せないということです。 その場合は、たとえば事前にプロパティを変数に代入しておく必要があります。 PHP 7.0.0 からは、括弧で囲むことでプロパティを直接呼び出せるようになりました。
例8 プロパティに格納した無名関数の呼び出し
class Foo
{
public $bar;
public function __construct() {
$this->bar = function() {
return 42;
};
}
}
$obj = new Foo();
// PHP 5.3.0 以降
$func = $obj->bar;
echo $func(), PHP_EOL;
// PHP 7.0.0 以降では、このようにすることもできます
echo ($obj->bar)(), PHP_EOL;
上の例の出力は以下となります。
42
クラスは、宣言部に extends キーワードを含めることで、他のクラスのメソッドと プロパティを継承することができます。多重継承を行うことはできず、クラスが継承できるベース クラスは一つだけです。
継承されたメソッドやプロパティをオーバーライドするには、 親クラスで定義されているのと同じ名前でそれを再宣言します。 しかし、親クラスでそのメソッドが final 定義されている場合はオーバーライドできません。 オーバーライドされた元のメソッドや静的プロパティにアクセスするには、 parent:: で参照します。
メソッドをオーバーライドするときには、パラメータのシグネチャも同じでなければなりません。
もし違っていれば、PHP は E_STRICT
レベルのエラーとなります。ただしコンストラクタは例外で、
異なるパラメータでオーバーライドすることができます。
例9 簡単なクラスの継承
<?php
class ExtendClass extends SimpleClass
{
// 親クラスのメソッドを再定義
function displayVar()
{
echo "Extending class\n";
parent::displayVar();
}
}
$extended = new ExtendClass();
$extended->displayVar();
?>
上の例の出力は以下となります。
Extending class a default value
PHP 5.5 以降では、class キーワードでクラス名の解決ができるようになりました。 ClassName クラスの完全修飾名を文字列で取得するには、 ClassName::class とします。 これは、 名前空間つきのクラスと組み合わせると特に便利です。
例10 クラス名の解決
<?php
namespace NS {
class ClassName {
}
echo ClassName::class;
}
?>
上の例の出力は以下となります。
NS\ClassName
注意:
::class によるクラス名の解決は、コンパイル時の変換です。 つまり、クラス名を作るタイミングでは、まだオートロードが行われていないということです。 結果的に、クラスがまだ存在しない時点でクラス名が展開されることになります。 この場合にはエラーは発生しません。