PHPのマジックメソッド一覧。概要だけざっくり確認したい時用のまとめ

PHPマジックメソッド一覧 ざっくり確認用まとめ マジックメソッド
※当サイトはアフィリエイト広告を掲載しています。

PHPにはマジックメソッドという機能があります。オブジェクトに対し、特定の動作を行った際に動作する(魔法のような?)メソッドのことです。

さて、そんなマジックメソッドなのですが、何となく使っている。もしくはまったく使ってないよ!と思われる方も多いのではないでしょうか。

実際はクラスのコンストラクタである__construct()もマジックメソッド。いつの間にか使っているものもあります。

たいした機能ではないのか……と言えば全くそんなことはなく、フレームワーク内の裏側では使われていることもあります。つまり上手く使えば便利な機能であることは間違いありません。

というわけで本ページでは、そんなマジックメソッドを「知る」まではいかなくとも「こんな機能のがあるよ」という確認用。かなりざっくりのご紹介です。

とりあえず俯瞰して全体をチェックしたいな、という場合に向いているページです。

Lara
Lara

詳細な解説ページは、ぼちぼちと作っていければいいなと思っています。

マジックメソッド一覧

執筆時(PHP8.3)のマジックメソッド一覧です。

メソッド名概要
__construct()クラスの新しいインスタンスが作成されるときに自動的に呼び出される。
__destruct()オブジェクトがガベージコレクションされる前やスクリプトの終了時に呼び出される。
__call($name, $arguments)オブジェクトからアクセス不可能なメソッドが呼び出されたときに実行。
__callStatic($name, $arguments)アクセス不可能な静的メソッドが呼び出されたときに実行。
__get($name)アクセス不可能なプロパティにアクセスしようとするときに呼び出される。
__set($name, $value)アクセス不可能なプロパティに値を設定しようとするときに呼び出される。
__isset($name)isset()関数をアクセス不可能なプロパティに使用したときに呼び出される。
__unset($name)unset()関数をアクセス不可能なプロパティに使用したときに呼び出される。
__sleep()serialize()関数がオブジェクトに適用される前に呼び出される。オブジェクトの保存すべきプロパティ名の配列を返す必要がある。
__wakeup()unserialize()関数でオブジェクトが再構築されるときに呼び出される。
__serialize()オブジェクトの状態をシリアライズするときに使用。プロパティの連想配列を返す。
__unserialize($data)シリアライズされたデータからオブジェクトを再構築。
__toString()オブジェクトを文字列として扱おうとするとき(例:echoで出力)に呼び出される。
__invoke($arguments)オブジェクトを関数のように呼び出そうとするときに実行。
__set_state($array)var_export()関数でエクスポートされたクラスの配列表現を受け取って、新しいクラスのインスタンスを生成するのに使用。
__clone()オブジェクトがクローンされるときに呼び出される。
__debugInfo()var_dump()関数でオブジェクトがダンプされるときに返すべき配列データを返す。

全部で17種類あります。

これから1つずつざっくりと説明していきますが、全部覚える必要は全くありません。

一般的なエンジニアにとっては必要になった時に「こんなのあったな」と思い出して検索できる程度で充分ではないでしょうか。

それでは長いですが見ていきましょう。

__constructor()

これはおなじみですよね。__construct() メソッドは、PHPのクラス内で最も頻繁に使用されるマジックメソッドです。

マジックメソッドというよりも「コンストラクタ」として認識している方も多いかもしれません。

このメソッドは、クラスの新しいインスタンスが作成される際に自動的に呼び出されます。オブジェクトの初期化や、必要な初期設定を行う目的で使用されます。

コード例

class SampleClass
{
    public $name;
    public $age;

    public function __construct($name, $age)
    {
        $this->name = $name;
        $this->age = $age;
        echo "SampleClassのインスタンスが作成されました!";
    }
}

$person = new SampleClass("Taro", 25); // この時点で__construct()が自動的に呼び出される
echo $person->name; // 出力: Taro
echo $person->age;  // 出力: 25

サンプルコードでは、SampleClassというクラスを定義し、その中に__construct()を持っています。

クラスの新しいインスタンスがnew SampleClass("Taro", 25)という形で作成される際に自動的に呼び出され、$name$ageの値がそれぞれオブジェクトのプロパティに設定されます。

Lara
Lara

以前はJava等と同じく、クラス名と同じメソッドがコンストラクタだったのですが、この方式の方が固定なので使いやすいと感じます。

__destruct()

__destruct() メソッドは、クラスのインスタンスが破棄される際に自動的に呼び出されるマジックメソッドです。__contruct()の真逆ですね。

PHPのガベージコレクションによってオブジェクトがメモリから解放される直前、またはスクリプトの実行が完了する時点でこのメソッドが呼び出されます。

リソースの解放や、終了時に行う必要がある特定の操作を、このメソッド内で行うことができます。

ガベージコレクションとは!?

不要になったメモリを自動的に解放する仕組みです。スクリプトが実行される際、変数やオブジェクトがメモリ上に確保されます。それらがもう使用されない状態になった時、カベージコレクションによりメモリ領域を再利用可能にします。

コード例

以下の例では、FileHandlerクラスを定義しています。このクラスは、ファイルを開いて内容を書き込むためのシンプルなハンドラとして機能します。

class FileHandler
{
    private $file;

    public function __construct($filename)
    {
        $this->file = fopen($filename, 'w');
        echo "ファイルが開かれました!<br>";
    }

    public function write($content)
    {
        fwrite($this->file, $content);
    }

    public function __destruct()
    {
        fclose($this->file);
        echo "ファイルが閉じられました!<br>";
    }
}

$fileHandler = new FileHandler('sample.txt');
$fileHandler->write('Hello, World!');

// スクリプトの終了時、またはオブジェクトが解放されると、__destruct() が自動的に呼び出される。

__construct()でファイルを開き、__destruct()でファイルを閉じる操作を自動的に行います。

このように、__destruct()はリソースのクリーンアップを自動化するのに便利なメソッドとなります。

__call()

__call() は、クラスのオブジェクトからアクセス不可能なメソッドが呼び出されたときに自動的に実行されるマジックメソッドです。

このメソッドは、メソッドの名前と、そのメソッドに渡される引数を受け取ります。

動的なメソッドの呼び出しや、存在しないメソッドの呼び出しに対してエラーをカスタマイズするときなどに役立ちます。

コード例

class Robot
{
    private function greet()
    {
        echo "Hello, Human!<br>";
    }

    public function __call($method, $arguments)
    {
        if ($method === 'sayHello') {
            $this->greet();
        } else {
            echo "Unknown method: {$method}<br>";
        }
    }
}

$robot = new Robot();
$robot->sayHello();  // 出力: Hello, Human!
$robot->doTask();    // 出力: Unknown method: doTask

上記の例では、Robot クラスには greet() というプライベートメソッドがあります。

sayHelloというメソッドは実際には存在しないのですが、クラスのインスタンスからそれを呼び出そうとすると__call()が実行され、代わりにgreet()メソッドが呼び出されます。

__callStatic()

__callStatic() は、アクセス不可能な静的メソッドが呼び出されたときに自動的に実行されるマジックメソッドです。

__call()がインスタンスメソッドに対して動作するのに対し、__callStatic()はstaticな静的メソッドの呼び出しに対して動作します。

コード例

class Toolkit
{
    private static function secretTool()
    {
        echo "Using the secret tool!<br>";
    }

    public static function __callStatic($method, $arguments)
    {
        if ($method === 'useTool') {
            self::secretTool();
        } else {
            echo "Unknown static method: {$method}<br>";
        }
    }
}

Toolkit::useTool();  // 出力: Using the secret tool!
Toolkit::doTask();   // 出力: Unknown static method: doTask

上記の例では、Toolkit クラスには secretTool() というプライベートな静的メソッドがあります。

useToolという静的メソッドは実際には存在しないのですが、それを呼び出そうとすると__callStatic()が実行され、代わりにsecretTool()メソッドが呼び出されます。

__get()

__get() メソッドは、クラスのオブジェクトからアクセス不可能なプロパティにアクセスしようとした時に自動的に実行されるマジックメソッドです。

アクセス不可能=privateやprotectedだったり、存在しないプロパティだったり等です。今後も何度かこの表現が出てきますので覚えて置いてください。

このメソッドは、アクセスしようとしたプロパティの名前を受け取ります。

オブジェクトの内部状態をカプセル化する際や、特定のプロパティに対するカスタムな取得処理を行いたい場合に役立ちます。

コード例

class UserProfile
{
    private $data = [
        'name' => 'John Doe',
        'age' => 30
    ];

    public function __get($property)
    {
        if (array_key_exists($property, $this->data)) {
            return $this->data[$property];
        } else {
            return "Property {$property} does not exist!";
        }
    }
}

$user = new UserProfile();
echo $user->name; // 出力: John Doe
echo $user->age;  // 出力: 30
echo $user->email; // 出力: Property email does not exist!

上記の例では、UserProfile クラス内で data 配列にいくつかのプロパティが設定されています。

このクラスのインスタンスから直接 data 配列の内容にアクセスすることはできませんが、__get() メソッドを使用することで配列内のデータにアクセスできるようになっています。

Lara
Lara

__get()や後述する__set()は、フレームワークでもよく利用されていますね!

__set()

__set()はクラスのオブジェクトに対してアクセス不可能なプロパティに値を設定しようとしたときに自動的に実行されるマジックメソッドです。

要は__get()の真逆であり、併せて使用されることが一般的です。

コード例

class UserProfile
{
    private $data = [
        'name' => 'John Doe',
        'age' => 30
    ];

    public function __get($property)
    {
        return $this->data[$property] ?? null;
    }

    public function __set($property, $value)
    {
        if (array_key_exists($property, $this->data)) {
            $this->data[$property] = $value;
        } else {
            echo "Property {$property} cannot be set!";
        }
    }
}

$user = new UserProfile();
echo $user->name;  // 出力: John Doe
$user->name = 'Jane Doe';
echo $user->name;  // 出力: Jane Doe
$user->email = 'jane@example.com'; // 出力: Property email cannot be set!

上記の例では、UserProfile クラス内で data 配列にいくつかのプロパティが設定されています。

このクラスのインスタンスから直接 data 配列の内容を変更することはできませんが、__set() メソッドを使用することで配列内のデータの設定ができるようになっています。

__isset()

__isset() は、isset() または empty() 関数をクラスのオブジェクトのアクセス不可能なプロパティに対して使用したときに、自動的に実行されるマジックメソッドです。

このメソッドは、確認しようとしたプロパティの名前を受け取ります。

__get()__set() と組み合わせて使用することで、プロパティの存在状態や、空かどうかのチェックをカスタマイズすることができます。

コード例

class Profile
{
    private $data = [
        'name' => 'Alice',
        'age' => 25,
    ];

    public function __isset($key)
    {
        return isset($this->data[$key]);
    }
}

$profile = new Profile();

if (isset($profile->name)) {
    echo "Name is set!";
} else {
    echo "Name is not set!";
}

// 出力: "Name is set!"

上記の例では、Profileクラスは非公開の配列プロパティ$dataを持っています。

外部から$profile->nameのようなアクセスを試みても、直接的にはアクセスできません。しかし、__isset()メソッドを実装することで、isset($profile->name)の形式でプロパティの存在確認ができるようになっています。

このように、__isset()はprivateやprotectedなプロパティの存在を外部から確認するために利用可能です。

Lara
Lara

正直、便利な使い所があまりまだ分かっていませんので研究したいです。

__unset()

__unset() は、unset() 関数をクラスのオブジェクトのアクセス不可能なプロパティに対して使用したときに、自動的に実行されるマジックメソッドです。

このメソッドは、削除しようとしたプロパティの名前を受け取ります。

このメソッドを使用することで、特定のプロパティの削除時にカスタムな動作を実行させることができます。

コード例

class UserProfile
{
    private $data = [
        'name' => 'John Doe',
        'age' => 30
    ];

    public function __get($property)
    {
        return $this->data[$property] ?? null;
    }

    public function __unset($property)
    {
        if (array_key_exists($property, $this->data)) {
            unset($this->data[$property]);
            echo "Property {$property} has been unset.<br>";
        } else {
            echo "Property {$property} does not exist.<br>";
        }
    }
}

$user = new UserProfile();
echo $user->name;  // 出力: John Doe
unset($user->name); // 出力: Property name has been unset.
echo $user->name;  // 出力: (何も表示されない)
unset($user->email); // 出力: Property email does not exist.

上記の例では、UserProfile クラス内で data 配列にいくつかのプロパティが設定されています。

このクラスのインスタンスのプロパティを削除する際、__unset() メソッドが実行され、data 配列内のプロパティの削除を行います。

__sleep()

__sleep() は、オブジェクトをシリアライズする前に自動的に実行されるマジックメソッドです。

このメソッドは、シリアライズする際にオブジェクトから保存されるプロパティの配列を返す必要があります。

つまり、特定のプロパティをシリアライズの結果から除外したい場合や、シリアライズ前のクリーンアップを行いたい場合にこのメソッドを利用します。

コード例

class UserProfile
{
    public $name = 'John Doe';
    private $password = 'secret123';

    public function __sleep()
    {
        // パスワードをシリアライズの結果から除外する
        return ['name'];
    }
}

$user = new UserProfile();
$serializedUser = serialize($user);
echo $serializedUser; // パスワードが含まれていないことが確認できます

上記の例では、UserProfile クラスには公開されている name プロパティとプライベートな password プロパティがあります。

__sleep() メソッドを使用して、シリアライズ時に password プロパティを除外しています。

__wakeup()

__wakeup() メソッドは、オブジェクトをデシリアライズする際(unserialize() 関数を使用するとき)に自動的に実行されるマジックメソッドです。要は__sleep()の対になるメソッドですね。

このメソッドは、オブジェクトのデシリアライズ後に必要な再初期化の処理やリソースの再接続などを行うためのものです。

たとえば、データベースへの接続リソースやファイルハンドルなど、シリアライズできないリソースを持つオブジェクトがあったとします。その場合、このメソッドを使用してデシリアライズ後にリソースを再確立することができます。

コード例

class DatabaseConnection
{
    private $connection;
    private $dsn = 'mysql:host=localhost;dbname=test';
    private $username = 'root';
    private $password = '';

    public function connect()
    {
        $this->connection = new PDO($this->dsn, $this->username, $this->password);
    }

    public function __sleep()
    {
        // データベース接続をクローズする(この例では実際の接続のクローズ処理は省略しています)
        return ['dsn', 'username', 'password'];
    }

    public function __wakeup()
    {
        // デシリアライズ後にデータベースに再接続する
        $this->connect();
    }
}

$db = new DatabaseConnection();
$db->connect();

$serializedDB = serialize($db);
$deserializedDB = unserialize($serializedDB);
// $deserializedDB はデシリアライズ後に自動的にデータベースに接続されます

この例では、DatabaseConnection クラスはデータベースへの接続を管理しています。

__sleep() を使用して、シリアライズ時にデータベース接続を閉じ、__wakeup() メソッドを使用して、デシリアライズ後にデータベースへ再接続しています。

__serialize()

PHP 7.4 から、__sleep()__wakeup() のよりモダンな代替手段として、__serialize()__unserialize() が導入されました。

PHP 7.4以降のプロジェクトであれば、こちらの利用を検討してみると良さそうです。

__serialize() は、オブジェクトをシリアライズする際、どのプロパティをシリアライズに含めるかを制御するためのものです。

このメソッドは、シリアライズされるプロパティの連想配列を返す必要があります。

コード例

class UserProfile
{
    private $name = 'John Doe';
    private $password = 'secret123';

    public function __serialize(): array
    {
        // passwordを除外し、nameのみをシリアライズに含める
        return ['name' => $this->name];
    }
}

$user = new UserProfile();
$serializedUser = serialize($user);
echo $serializedUser; // パスワードが含まれていないことが確認できます

この例では、UserProfile クラスには namepassword の2つのプライベートプロパティがあります。

__serialize() を使用して、シリアライズ時に password プロパティを除外しています。

__serialize()__sleep() とは異なり、連想配列を返すことに注意が必要です。

このメソッドを利用することにより、プロパティの値を直接操作したり、新しい値を追加したりすることが容易になります。

__unserialize()

__unserialize() は、オブジェクトをデシリアライズする際に使用されます。

このメソッドは、__serialize() と密接に関連しており、unserialize() 関数によってオブジェクトがデシリアライズされるときに自動的に呼び出されます。

__unserialize() は、__serialize() が返すデータ(連想配列)を引数として受け取り、それを使用してオブジェクトの状態を復元します。

コード例

class UserProfile
{
    private $name;
    private $password = 'secret123'; // 初期値が設定されています

    public function __serialize(): array
    {
        return ['name' => $this->name];
    }

    public function __unserialize(array $data): void
    {
        $this->name = $data['name'];
        // passwordプロパティはデシリアライズされませんが、初期値を保持しています
    }
}

$user = new UserProfile();
$serializedUser = serialize($user);
$restoredUser = unserialize($serializedUser);
// $restoredUser はデシリアライズされ、nameプロパティが復元されます

この例では、UserProfile クラスは name プロパティと password プロパティを持っています。

__serialize() メソッドを使用して、name プロパティのみをシリアライズに含め、__unserialize() メソッドを使用してデシリアライズ時に name プロパティの状態を復元しています。

__toString()

__toString() は、オブジェクトを文字列として表現する際に使用されるマジックメソッドです。

このメソッドは、echoprint のような文字列コンテキストでオブジェクトを使用する場合や、文字列操作関数にオブジェクトを渡す場合に自動的に呼び出されます。

このメソッドは、当然のことながら文字列を返す必要があります。

コード例

class Book
{
    private $title;
    private $author;

    public function __construct($title, $author)
    {
        $this->title = $title;
        $this->author = $author;
    }

    public function __toString()
    {
        return "「" . $this->title . "」 by " . $this->author;
    }
}

$book = new Book("道は開ける", "デール・カーネギー");
echo $book; // 出力: 「"道は開ける」 by デール・カーネギー

この例では、Book クラスはタイトルと著者の情報を持っています。

__toString() メソッドを使用して、オブジェクトを文字列として表現する方法を定義しています。そのため、echo でオブジェクトを直接出力することができます。

__invoke()

__invoke() は、オブジェクトを関数のように呼び出そうとした時に実行されるマジックメソッドです。

特定のクラスのインスタンスをコールバック関数として利用したり、処理をカプセル化したりすることが可能です。

コード例

class Multiplier
{
    private $factor;

    public function __construct($factor)
    {
        $this->factor = $factor;
    }

    public function __invoke($value)
    {
        return $value * $this->factor;
    }
}

$double = new Multiplier(2);
echo $double(5);  // 出力: 10

$triple = new Multiplier(3);
echo $triple(5);  // 出力: 15

この例では、Multiplier クラスは与えられた数値に特定の係数を掛ける役割を持っています。

__invoke() メソッドにより、$double$triple のようなオブジェクトを関数のように扱うことができます。

こちらは詳細な以下ページで詳細な解説をしていますので、ご興味があれば参照ください。

__set_state()

__set_state() は、var_export() 関数でエクスポートされたクラスの情報を基に、新しいオブジェクトのインスタンスを作成するために使用されます。

var_export()とは

var_export() は、PHPで提供される関数の一つで、変数の内容を文字列として返すか、あるいは出力するためのものです。この関数の特徴的な点は、返される文字列が有効なPHPコードであり、これを再度実行することで元の変数を復元できるということです。

print_r()var_dump() といった関数も変数の内容を出力する目的で使用されますが、var_export() の返す内容がPHPコードとして再利用可能である点が異なります。

__set_state() は、var_export() によって出力された結果を評価 (eval()) する際に呼び出されます。

このメソッドは静的メソッドとして定義され、引数としてプロパティの配列を受け取り、新しいオブジェクトのインスタンスを返す必要があります。

コード例

class Point
{
    private $x;
    private $y;

    public function __construct($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }

    public static function __set_state($array)
    {
        return new self($array['x'], $array['y']);
    }
}

$point = new Point(2, 3);
$exported = var_export($point, true);
$restoredPoint = eval("return $exported;");

// $restoredPoint は $point と同じ情報を持つ新しいインスタンスです

この例では、Point クラスは 2D の点を表現します。

__set_state() を使用して、var_export() によってエクスポートされた情報から新しい Point オブジェクトを作成しています。

Lara
Lara

ぶっちゃけ、これだけの説明では分かりづらいので、いずれ詳細ページを作ります。

__clone()

__clone() は、clone キーワードを使用してオブジェクトがクローンされる時に自動的に呼び出されるマジックメソッドです。

このメソッドは、オブジェクトの複製時に特定の動作や状態の調整を行う場合に便利です。

デフォルトのクローニング操作は、オブジェクトのシャローコピー(浅いコピー)を作成します。

しかし、オブジェクト内部に他のオブジェクトへの参照や特定のリソースへの参照がある場合、深いコピー(新しいオブジェクトのインスタンスを作成するなど)やリソースの再初期化などの追加操作を行うことが必要になることがあります。

このようなケースで__clone() メソッドを使用することで、クローニング時の特定の動作をカスタマイズできます。

コード例

class DateRange
{
    private $start;
    private $end;

    public function __construct(DateTime $start, DateTime $end)
    {
        $this->start = $start;
        $this->end = $end;
    }

    public function __clone()
    {
        // DateTime オブジェクトをクローンすることで、新しいインスタンスを作成
        $this->start = clone $this->start;
        $this->end = clone $this->end;
    }
}

$start = new DateTime('2022-01-01');
$end = new DateTime('2022-12-31');
$range = new DateRange($start, $end);

$clonedRange = clone $range;
// $clonedRange の start と end は新しい DateTime オブジェクトのインスタンスを参照

この例では、DateRange クラスは2つの DateTime オブジェクトをプロパティとして保持しています。

__clone() 内で、これらの DateTime オブジェクトをクローンすることで、新しいインスタンスを作成しています。

__debugInfo()

__debugInfo() は、var_dump() 関数を使用してオブジェクトをダンプしたときの出力情報をカスタマイズするためのマジックメソッドです。

このメソッドは配列を返すことが期待され、返された配列の内容が var_dump() で表示されます。

例えば、オブジェクトが内部的な状態や大きなデータを持っていて、デバッグ出力でそれを表示したくない場合や、特定の形式でデバッグ情報を表示したい場合などに、このメソッドを使用してカスタマイズできます。

コード例

class User
{
    private $id;
    private $name;
    private $password;  // この情報はデバッグ出力に表示したくない

    public function __construct($id, $name, $password)
    {
        $this->id = $id;
        $this->name = $name;
        $this->password = $password;
    }

    public function __debugInfo()
    {
        // password を除いた情報を返す
        return [
            'id' => $this->id,
            'name' => $this->name,
            'info' => 'password is hidden for security reasons'
        ];
    }
}

$user = new User(1, "Alice", "secret1234");
var_dump($user);

この例では、User クラスはユーザのID、名前、およびパスワードをプロパティとして保持しています。

セキュリティの観点から、__debugInfo() を使用して、パスワードの情報はデバッグ出力に表示しないようにしています。

まとめ

お疲れ様でした!非常に長かったですね。__constructor()のように頻繁に使うものもあれば、ほとんど使わないようなものもあります。

また、分かりやすいものもあれば、一見して機能が分かりづらいものもあります。

一通り知識として知っておくことで、何かのひょうしに「使えるかな」と思い出すことができれば良いのではないでしょうか。

なお、これらのマジックメソッドは各種フレームワークで利用されていることがあります。例えば人気のLaravelなどでも裏側で使われており、その使い方はさすがに洗練されています。

まずはそれらでの使用例を参考にしてみると良いかもしれませんね。

コメント

タイトルとURLをコピーしました