PHP 上級試験範囲 オブジェクト 個人的な備忘録

# インターフェース基礎

**インターフェース**は、抽象メソッドの集まりに名前を付けたもの。インターフェースを使用すると、そのインターフェースを持つクラスが備えるべき機能を明示することができる。インターフェースのインスタンスを作成することはできない。

インターフェースは`interface`キーワードで定義する。インターフェース内のメソッドは`abstract`キーワードを付けないが、抽象メソッドとして扱われる。

**抽象メソッドを持つインターフェースの定義**

```php:php
interface X {
    function a() // 抽象メソッド
}
```

クラスにインターフェースを持たせることを**実装**という。
※抽象メソッドとをサブクラスで具体的に定義することも実装と呼ぶ。

インターフェースを実装するには、クラス名の後ろに`implements`キーワードを置き、実装するインターフェース名を記述する。インターフェースを実装するクラスでは、インターフェースのすべての抽象メソッドを実装するか、またはそのクラスを抽象クラスにする。

**インターフェースのすべての抽象メソッドの実装**

```php:php
interface X {
    function a() // 抽象メソッド
}

class Y implements X {
    function a() {
        // 処理
    }
}
```

**エラーになる例**

```php:php
interface X {
    function a() // 抽象メソッド
    function b() // 抽象メソッド
}

class Y implements X {
    function a() {
        // 処理
    }
}
```

インターフェースにプロパティを定義することはできない。

# クラスの継承と、インターフェースの実装

クラスの定義の際に、一度に複数のスーパークラスを継承することはできない。これは抽象クラスにおいても同様である。但し、クラスを継承するクラスを作り、さらにそのクラスを継承するクラスを定義する（サブクラスのサブクラスを作る）ことはできる。

クラスが一度に複数のインターフェースを実装することは可能である。その場合は、`implements`キーワードの後ろに、実装するインターフェースの名前をカンマ区切りで複数指定する。

```php:php
interface X {
    function a() // 抽象メソッド
}

interface Y {
    function b() // 抽象メソッド
}

class Z implements X, Y {
    function a() {
        // 処理
    }

    function b() {
        // 処理
    }

}
```

# タイプヒンティング

**タイプヒンディング**とは、メソッドのパラメータに対し、特定のクラスやインターフェースを指定することができる機能である。タイプヒンディングにより、パラメータに渡された引数が、特定のクラスやインターフェースのインスタンスを強制することができる。つまり、誤ったパラメータを渡すのを防ぐことができる。

```php:php
class X {
    // 処理
}

class Y {
    // 処理
}

class Z {

    // パラメータの$objがクラスXのインスタンスでなければいけないことを宣言している。
    function a (X $obj) {
        echo 'OK';
    }
}

$z = new Z();
$z->a(new X);
```

タイプヒンディングで、パラメータに渡された引数が、配列であることも強制できる。この場合はパラメータ名の前に`array` を記述する。`int`や`string`は指定できない。

パラメータに渡された引数が、タイプヒンディングで指定された型のインスタンスでない場合は、「**キャッチ可能な致命的なエラー**」が発生する。エラーハンドラ関数を用いて、**例外**に変換することができる。try-cache構文でその例外をキャッチすることで、例外に対処するコードを実行することができる。

# クラスの調査

**内部検査**の機能を使うと、クラスやオブジェクトのプロパティ、メソッドなどの性質を調べることができる。

## class_exists()

`class_exists()`は、指定した名前のクラスが定義済みかどうかを確認する。

## get_declared_classes()

`get_declared_classes()`は、定義されたすべてのクラス名を配列で返す。

## get_class_methods()

`get_class_methods()`は、指定されたクラスのメソッド名（静的メソッド名を含む）の一覧を取得することができる。継承したメソッドも取得する事ができる。

## get_class_vars()

`get_class_vars()`は、指定されたクラスのプロパティと、それらのデフォルト値を取得する。

## get_parent_class()

`get_parent_class()`は、オブジェクト（またはクラス）の親クラスの名前を取得する。対応する親クラスがない場合は、`false`を返す。

# オブジェクトの調査

## is_object()

`is_object()`を用いると、指定された値がオブジェクトかどうかを調べることができる。

## get_class()

`get_class()`を用いると、指定されたオブジェクトのクラス名を取得できる。

## method_exists()

`method_exists()`を用いると、オブジェクト（またはクラス）が、指定した名前のメソッドを持つかどうかを調べる事ができる。

## get_object_vars()

`get_object_vars()`は、指定されたオブジェクトについて、現在のスコープからアクセス可能なプロパティと、それらの現在の値を取得する。静的プロパティの情報は含まれない。引数にオブジェクトでないものを渡した場合は`NULL`を返す。

# シリアライズ

オブジェクトの**シリアライズ**とは、オブジェクトをバイトストリームに変換する事である。シリアライズする事で、オブジェクトをファイルに保存できるようになる。また、シリアライズされたオブジェクトは、元の形に**復元**する事ができる。PHPのセッションの機能では、シリアライズと復元が使用されている。

シリアライズには`serialize()`を使用する。シリアライズによって得られたバイトストリームを元のオブジェクトに復元するには`unserialize()`を使用する。なお、シリアライズではオブジェクト以外にもリソース型以外のすべての変数で利用可能である。

```php:php
class X {
	public $a;
	public $b;
}

$x = new X;
$x->a = 'hello';
$x->b = 5;

$s = serialize($x);
echo $s;
// 結果：O:1:"X":2:{s:1:"a";s:5:"hello";s:1:"b";i:5;}

$y = unserialize($s);
var_dump($y);

/*
結果：
object(X)#2 (2) {
  ["a"]=>
  string(5) "hello"
  ["b"]=>
  int(5)
}
*/
```
クラスに`__sleep()`が含まれている場合、シリアライズの直前にそのメソッドが呼び出される。クラスに`__wakeup()`が含まれている場合、復元の直後にそのメソッドが呼び出される。

# 参照

徹底攻略 PHP5 技術者認定 [上級] 試験問題集 [PJ0-200]対応