Php/docs/language.oop5.magic

提供:Dev Guides
< Php
移動先:案内検索

マジックメソッド

以下の関数名 __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone() および __debugInfo() は、PHP クラスにおける特殊関数の名前です。 これらの関数に関連する特別な機能を使用する場合を除き、 クラス内にこれらの名前を有する関数を作成してはいけません。

注意:

全てのマジックメソッドは public として宣言されていなければ なりません

警告 PHP は、__ で始まる関数名を特殊関数として取り置きしてあります。 このページに記載されているような特殊な機能を必要としないのであれば、 関数名を __ で始めないほうが良い。


=== __sleep()__wakeup() ===

public __sleep ( ) : array

public __wakeup ( ) : void

serialize() は、クラスに特殊な名前 __sleep() の関数があるかどうかを調べます。 もしあれば、シリアル化の前にその関数を実行します。 この関数で、オブジェクトをクリアすることができます。 またこの関数は、シリアル化するオブジェクトについて、 すべての変数の名前を配列で返すことが前提となっています。 このメソッドが何も返さなかった場合は、null がシリアル化され、E_NOTICE が発生します。

注意:

__sleep() で、親クラスの private プロパティの名前を返すことはできません。 そうしようとすると E_NOTICE レベルのエラーとなります。 この場合は、かわりに Serializable インターフェイスを使います。

典型的な __sleep() の使用法は、 途中のデータをコミットしたり、 似たようなタスクのクリアを行うといったものです。 また、オブジェクトが非常に大きく、かつ、完全に保存する必要がない場合、 この関数が有用です。

逆に、unserialize() は、 特殊な名前 __wakeup() を有する 関数の存在を調べます。 もし存在する場合、この関数は、オブジェクトが有する可能性が あるあらゆるリソースを再構築することができます。

__wakeup() の使用目的は、 シリアル化の際に失われたデータベース接続を再度確立したり、 その他の再初期化を行うことです。

例1 sleep および wakeup

<?phpclass Connection{    protected $link;    private $dsn, $username, $password;        public function __construct($dsn, $username, $password)    {        $this->dsn = $dsn;        $this->username = $username;        $this->password = $password;        $this->connect();    }        private function connect()    {        $this->link = new PDO($this->dsn, $this->username, $this->password);    }        public function __sleep()    {        return array('dsn', 'username', 'password');    }        public function __wakeup()    {        $this->connect();    }}?>

=== __serialize()__unserialize() ===

public __serialize ( ) : array

public __unserialize ( array $data ) : void

serialize() は、クラスが 特殊な名前 __serialize() を持つかを調べます。 もしあれば、シリアル化の前にその関数を実行します。 この関数は、オブジェクトをシリアル化した状態を示すキー/値のペアを連想配列にして返さなければなりません。 配列を返さなかった場合、TypeError がスローされます。

注意:

__serialize()__sleep() が両方同じオブジェクトに定義されていた場合、 __serialize() だけが呼び出されます。 __sleep() は無視されます。 オブジェクトが Serializable インターフェイスを実装していた場合、 インターフェイスの serialize() メソッドは無視され、 __serialize() が代わりに使われます。

__serialize() の目的は、 任意のオブジェクトの表現をシリアライズしやすいように定義することです。 配列の要素はオブジェクトのプロパティに対応していても構いませんが、必須ではありません。

逆に、unserialize() は 特殊な名前 __unserialize() を持つかを調べます。 もしあれば、__serialize() が返した配列を復元し、この関数に渡します。 この関数では、その配列から必要に応じてオブジェクトのプロパティを復元して構いません。

注意:

__unserialize()__wakeup() が両方同じオブジェクトに定義されていた場合、 __unserialize() だけが呼び出されます。 __wakeup() は無視されます。

注意:

この機能は PHP 7.4.0 以降で利用できます。

例2 Serialize および unserialize

<?phpclass Connection{    protected $link;    private $dsn, $username, $password;    public function __construct($dsn, $username, $password)    {        $this->dsn = $dsn;        $this->username = $username;        $this->password = $password;        $this->connect();    }    private function connect()    {        $this->link = new PDO($this->dsn, $this->username, $this->password);    }    public function __serialize(): array    {        return [          'dsn' => $this->dsn,          'user' => $this->username,          'pass' => $this->password,        ];    }    public function __unserialize(array $data): void    {        $this->dsn = $data['dsn'];        $this->username = $data['user'];        $this->password = $data['pass'];        $this->connect();    }}?>

__toString()

public __toString ( ) : string

__toString() メソッドにより、 クラスが文字列に変換される際の動作を決めることができます。たとえば echo $obj; としたときに何を表示させるかといったことです。 このメソッドは文字列を返さなければなりません。それ以外の場合は E_RECOVERABLE_ERROR レベルの致命的なエラーが発生します。

警告 PHP 7.4.0 より前のバージョンでは、__toString() メソッド内から例外を投げることはできません。そうした場合、致命的なエラーが発生します。


例3 簡単な例

<?php// 簡単なクラスを宣言class TestClass{    public $foo;    public function __construct($foo)    {        $this->foo = $foo;    }    public function __toString()    {        return $this->foo;    }}$class = new TestClass('Hello');echo $class;?>

上の例の出力は以下となります。


Hello

注意が必要なのは、PHP 5.2.0 より前では、 __toString() メソッドは echo または print と直接結合された場合のみコールされていたということです。 PHP 5.2.0 以降では、これはすべての文字列コンテキスト (たとえば printf() における %s 修飾子) でコールされます。しかし、その他の型のコンテキスト (たとえば %d 修飾子) ではコールされません。 PHP 5.2.0 以降では、__toString() メソッドを持っていないオブジェクトを文字列に変換しようとすると E_RECOVERABLE_ERROR が発生します。


__invoke()

__invoke ( ...$values ) : mixed

__invoke() メソッドは、 スクリプトがオブジェクトを関数としてコールしようとした際にコールされます。

注意:

この機能は PHP 5.3.0 以降で使用可能です。

例4 __invoke() の使用

<?phpclass CallableClass{    public function __invoke($x)    {        var_dump($x);    }}$obj = new CallableClass;$obj(5);var_dump(is_callable($obj));?>

上の例の出力は以下となります。


int(5)
bool(true)

__set_state()

static __set_state ( array $properties ) : object

この static メソッドは、 PHP 5.1.0 以降で var_export() によって エクスポートされたクラスのためにコールされます。

このメソッドの唯一のパラメータは、エクスポートされたプロパティを array('property' => value, ...) の形式で保持する配列です。

例5 __set_state() の使用法 (PHP 5.1.0 以降)

<?phpclass A{    public $var1;    public $var2;    public static function __set_state($an_array) // PHP 5.1.0 以降    {        $obj = new A;        $obj->var1 = $an_array['var1'];        $obj->var2 = $an_array['var2'];        return $obj;    }}$a = new A;$a->var1 = 5;$a->var2 = 'foo';eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(                                            //    'var1' => 5,                                            //    'var2' => 'foo',                                            // ));var_dump($b);?>

上の例の出力は以下となります。


object(A)#2 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
}

注意:

var_export() でオブジェクトをエクスポートする際に、そのオブジェクトのクラスが __set_state() を実装しているかどうかは確認しません。 一部の内部クラスを扱う際に、この影響が出てきます。 エクスポートしたオブジェクトをインポートする際に、 __set_state() を実装するクラスのものだけをインポートさせるようにするのは、プログラマーの責務となります。

__debugInfo()

__debugInfo ( ) : array

このメソッドは、var_dump() がオブジェクトをダンプするときに、 プロパティの情報を取得するために呼ばれます。 もしオブジェクトにこのメソッドが定義されていなければ、 すべての public, protected, private プロパティを表示します。

この機能は PHP 5.6.0 で追加されました。

例6 __debugInfo() の使用法

<?phpclass C {    private $prop;    public function __construct($val) {        $this->prop = $val;    }    public function __debugInfo() {        return [            'propSquared' => $this->prop ** 2,        ];    }}var_dump(new C(42));?>

上の例の出力は以下となります。


object(C)#1 (1) {
  ["propSquared"]=>
  int(1764)
}