PHP基礎構文　マジックメソッドを全て利用してみる

# 前提
- 実行環境
    - **PHP 7.1.32**
- 本エントリーでは、PHPが用意する全マジックメソッドに関する挙動について触れる

# マジックメソッドとは
> インスタンスがある特定の条件になったときに、明示的にcallしなくても暗黙的にcallされるメソッド

**引用元**：[便利だけど使いどころが難しいPHPの代表的なマジックメソッドと無名関数の使い方](https://www.atmarkit.co.jp/ait/articles/1509/03/news021.html)

- **暗黙的**にコールされる事がポイント

## __construct()
- オブジェクトが生成されるたびにコールされるメソッド
    - 参考：https://www.php.net/manual/ja/language.oop5.decon.php#object.construct

```php
class Message
{
    public function __construct()
    {
        print 'call ' . __METHOD__ . PHP_EOL;
    }
}

var_dump(new Message());

/* 出力結果 */
call Message::__construct
object(Message)#1 (0) {
}
```

## __destruct()
- オブジェクトを参照するメソッドが１つもなくなった時（全てコールされた後）にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.decon.php#object.destruct

```php
class Message
{
    public function __construct()
    {
        print 'call ' . __METHOD__ . PHP_EOL;
    }

    public function __destruct()
    {
        print 'call ' . __METHOD__ . PHP_EOL;
    }
}

var_dump(new Message());

/* 出力結果 */
call Message::__construct
object(Message)#1 (0) {
}
call Message::__destruct
```

## __call()
- アクセス不能なメソッド（未定義のメソッドやプライベートなメソッドなど）に対してアクセスした時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.overloading.php#object.call

```php
<?php

class Message
{
    public function __call(string $name, array $arguments)
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        print 'Value of first argument $name: ' . $name . PHP_EOL;
        print 'Value of second argument $arguments: ' . implode($arguments) . PHP_EOL;
    }
}

$message = new Message();
$message->getMessage('Hello');
var_dump($message);

/* 出力結果 */
call Message::__call
Value of first argument $name: getMessage
Value of second argument $arguments: Hello
object(Message)#1 (0) {
}
```

## __callStatic()
- アクセス不能メソッドを静的にアクセスした時にコールされるメソッド

```php
class Message
{
    public static function __callStatic(string $name, array $arguments)
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        print 'Value of first argument $name: ' . $name . PHP_EOL;
        print 'Value of second argument $arguments: ' . implode($arguments) . PHP_EOL;
    }
}

$message = new Message();
$message::getMessage('Hello');
var_dump($message);

/* 出力結果 */
call Message::__callStatic
Value of first argument $name: getMessage
Value of second argument $arguments: Hello
object(Message)#1 (0) {
}
```

## __get()
- アクセス不能なプロパティ（未定義のプロパティやプライベートなプロパティなど）に対してアクセスした時にコールされるメソッド（主に、データの読み込む際に使用する）
    - 参考： https://www.php.net/manual/ja/language.oop5.overloading.php#object.get

```php
<?php

class Message
{
    private $message = [];

    public function __get(string $name)
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        print 'Value of first argument $name: ' . $name . PHP_EOL;
        return $this->message;
    }
}

$message = new Message();
var_dump($message->message);

/* 出力結果 */
call Message::__get
Value of first argument $name: message
array(0) {
}
```

## __set()
- アクセス不能なプロパティ（未定義のプロパティやプライベートなプロパティなど）に対してアクセスした時にコールされるメソッド（主に、データの書き込む際に使用する）
    - 参考： https://www.php.net/manual/ja/language.oop5.overloading.php#object.set

```php
<?php

class Message
{
    private $message = [];

    public function __get(string $name)
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        print 'Value of first argument $name: ' . $name . PHP_EOL;
        if (array_key_exists($name, $this->message)) {
            return true;
        } else {
            return false;
        }
    }

    public function __set(string $name, $value)
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        print 'Value of first argument $name: ' . $name . PHP_EOL;
        print 'Value of second argument $value: ' . $value . PHP_EOL;
        $this->message[$name] = $value;
        print PHP_EOL;
    }
}

$message = new Message();
$message->message = 'Hello';
var_dump($message->message);

/* 出力結果 */
call Message::__set
Value of first argument $name: message
Value of second argument $value: Hello

call Message::__get
Value of first argument $name: message
bool(true)
```

## __isset()
- アクセス不能なプロパティ（未定義のプロパティやプライベートなプロパティなど）に対して、issetやemptyを実行した時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.overloading.php#object.isset

```php
<?php

class Message
{
    private $message = [];

    public function __isset(string $name)
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        print 'Value of first argument $name: ' . $name . PHP_EOL;
        return isset($this->message[$name]);
    }
}

$message = new Message();
var_dump(isset($message->message));

/* 出力結果 */
call Message::__isset
Value of first argument $name: message
bool(false)
```

## __unset()
- アクセス不能なプロパティ（未定義のプロパティやプライベートなプロパティなど）に対して、unsetを実行した時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.overloading.php#object.unset

```php
<?php

class Message
{
    private $message = [];

    public function __unset(string $name)
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        print 'Value of first argument $name: ' . $name . PHP_EOL;
        unset($this->message[$name]);
    }
}

$message = new Message();
unset($message->message);

/* 出力結果 */
call Message::__unset
Value of first argument $name: message
```

## __sleep()
- [serialize()](https://www.php.net/manual/ja/function.serialize.php)をコールした時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.magic.php#object.sleep

```php
class Message
{
    public function __sleep()
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        return [];
    }
}
$message = new Message();
var_dump(serialize($message));

/* 出力結果 */
call Message::__sleep
string(18) "O:7:"Message":0:{}"
```

## __wakeup()
- [unserialize()](https://www.php.net/manual/ja/function.unserialize.php)をコールした時にコールされるメソッド

```php
class Message
{
    public function __wakeup()
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        return [];
    }
}
$message = new Message();
$serializedMessage = serialize($message);
var_dump(unserialize($serializedMessage));

/* 出力結果 */
call Message::__wakeup
object(Message)#2 (0) {
}
```

## __toString()
- インスタンスを文字列として出力する時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.magic.php#object.tostring

```php
class Message
{
    public function __toString()
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        return 'Hello' . PHP_EOL;
    }
}

$message = new Message();
echo $message;

/* 出力結果 */
call Message::__toString
Hello
```

## __invoke()
- オブジェクトを関数としてコールした時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.magic.php#object.invoke

```php
class Message
{
    public function __invoke($value)
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        echo $value . PHP_EOL;
    }
}

$message = new Message();
$message('Hello');
var_dump($message);

/* 出力結果 */
call Message::__invoke
Hello
object(Message)#1 (0) {
}
```

## __set_state()
- [var_export()](https://www.php.net/manual/ja/function.var-export.php)によってエクスポートされた時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.magic.php#object.set-state

```php
class Message
{
    public $val_a;
    public $val_b;

    public static function __set_state(array $properties)
    {
        $this->val_a = $properties['val_a'];
        $this->val_b = $properties['val_b'];
        print 'call ' . __METHOD__ . PHP_EOL;
    }
}

$message = new Message();
$message->val_a = 'Hello';
$message->val_b = 'Good morning';
var_export($message);

/* 出力結果 */
Message::__set_state(array(
   'val_a' => 'Hello',
   'val_b' => 'Good morning',
))
```

## __clone()
- クローンキーワードによってオブジェクトをコールした時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.cloning.php#object.clone

```php
class Message
{
    public function __clone()
    {
        print 'call ' . __METHOD__ . PHP_EOL;
    }
}

$message = new Message();
var_dump(clone $message);

/* 出力結果 */
call Message::__clone
object(Message)#2 (0) {
}
```

## __debugInfo()
- [var_dump()](https://www.php.net/manual/ja/function.var-dump.php)によってオブジェクトをコールした時にコールされるメソッド
    - 参考： https://www.php.net/manual/ja/language.oop5.magic.php#object.debuginfo

```php
class Message
{
    public function __debugInfo()
    {
        print 'call ' . __METHOD__ . PHP_EOL;
        return [];
    }
}

var_dump(new Message());

/* 出力結果 */
call Message::__debugInfo
object(Message)#1 (0) {
}
```