クラスの基礎
class
各クラスの定義は、class
キーワードで始まり、クラス名が続きます。
そしてその後に波括弧のペアが続き、
その中にはクラスのプロパティとメソッドの定義を記述します。
クラス名には、PHP の予約語
以外でラベルとして有効なあらゆる名前を使用することができます。
有効なクラス名は、先頭が文字あるいはアンダースコアで始まり、
その後に任意の数の文字/数字/アンダースコアが続くものです。
正規表現で表すと、
^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$
のようになります。
クラスの中には、 定数 や 変数 ("プロパティ" といいます) そして関数 ("メソッド" といいます) を含めることができます。
例1 簡単なクラス定義
<?phpclass 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 の通知が出るでしょう。
<?phpclass 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
キーワードを使わなければなりません。エラー時に
例外をスローするような
コンストラクタを定義していない限り、
オブジェクトが常に生成されます。
クラスは、そのインスタンスを作成する前に定義しなければなりません
(これが必須となる場合もあります)。
クラス名を含む文字列を 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 新しいオブジェクトの作成
<?phpclass 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 新しく作成したオブジェクトのメンバーへのアクセス
<?phpecho (new DateTime())->format('Y');?>
上の例の出力は、 たとえば以下のようになります。
2016
注意:
PHP 7.1 より前のバージョンでは、コンストラクタが定義されない場合、それへの引数が評価されていませんでした。
プロパティとメソッド
クラスのプロパティとメソッドは、それぞれ別の "名前空間" に存在するので、 同じ名前のプロパティとメソッドを共存させることもできます。 プロパティを参照する場合もメソッドを参照する場合も書きかたは同じです。 それがプロパティへのアクセスなのかメソッドの呼び出しなのかは、そのコンテキストによって決まります。 つまり、変数にアクセスしようとしているのか関数を呼び出そうとしているのかの違いです。
例7 プロパティへのアクセスとメソッドの呼び出し
<?phpclass 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 プロパティに格納した無名関数の呼び出し
<?phpclass 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
クラスは、宣言部に extends
キーワードを含めることで、他のクラスのメソッドと
プロパティを継承することができます。多重継承を行うことはできず、クラスが継承できるベース
クラスは一つだけです。
継承されたメソッドやプロパティをオーバーライドするには、 親クラスで定義されているのと同じ名前でそれを再宣言します。 しかし、親クラスでそのメソッドが final 定義されている場合はオーバーライドできません。 オーバーライドされた元のメソッドや静的プロパティにアクセスするには、 parent:: で参照します。
メソッドをオーバーライドするときには、パラメータのシグネチャも同じでなければなりません。
もし違っていれば、PHP は E_STRICT
レベルのエラーとなります。ただしコンストラクタは例外で、
異なるパラメータでオーバーライドすることができます。
例9 簡単なクラスの継承
<?phpclass ExtendClass extends SimpleClass{ // 親クラスのメソッドを再定義 function displayVar() { echo "Extending class\n"; parent::displayVar(); }}$extended = new ExtendClass();$extended->displayVar();?>
上の例の出力は以下となります。
Extending class a default value
::class
class
キーワードでもクラス名の解決を行うことが出来ます。
ClassName
クラスの完全修飾名を文字列で取得するには、
ClassName::class
とします。
これは、
名前空間つきのクラスと組み合わせると特に便利です。
例10 クラス名の解決
<?phpnamespace NS { class ClassName { } echo ClassName::class;}?>
上の例の出力は以下となります。
NS\ClassName
注意:
::class
によるクラス名の解決は、コンパイル時の変換です。 つまり、クラス名を作るタイミングでは、まだオートロードが行われていないということです。 結果的に、クラスがまだ存在しない時点でクラス名が展開されることになります。 この場合にはエラーは発生しません。例11 クラス名が存在しない場合の名前解決
<?phpprint Some\Class\DoesNot\Exist::class;?>
上の例の出力は以下となります。
Some\Class\Does\Not\Exist
PHP 8.0.0 以降では、
::class
はオブジェクトに対しても使えるようになりました。
この名前解決はコンパイル時ではなく、実行時に行われます。
この場合、get_class() をオブジェクトに対して使った時と同じ動きをします。
例12 オブジェクトの名前解決
<?phpnamespace NS { class ClassName { }}$c = new ClassName();print $c::class;?>
上の例の出力は以下となります。
NS\ClassName
nullsafe メソッドとプロパティ
PHP 8.0.0 以降では、プロパティやメソッドは
"nullsafe" 演算子 ?->
を使ってアクセスすることもできます。
nullsafe 演算子は既に述べたメソッドやプロパティと同じように振る舞いますが、
オブジェクトが null
と評価された場合に、例外はスローされず、
null
が返される点だけが異なります。
オブジェクトの評価がチェインの一部だった場合は、
残りのチェインはスキップされます。
この演算子の働きは、 オブジェクトにアクセスするたびに is_null() でラップするコードに似ています。 しかし、よりコンパクトです。
例13 nullsafe 演算子
<?php// PHP 8.0.0 以降は、このように書けます:$result = $repository?->getUser(5)?->name;// これは、以下のコードチェックと同等です:if (is_null($repository)) { $result = null;} else { $user = $repository->getUser(5); if (is_null($user)) { $result = null; } else { $result = $user->name; }}?>
注意:
nullsafe 演算子は、プロパティやメソッドが値を返す際、 null が正しく、期待されうる値とみなせる場合に一番よく使います。 エラーを示すためなら、例外を投げるほうが好ましいです。