マジックメソッドとは
コンストラクタ「__construct()」等のアンダースコア2つから始まるメソッドで、
基本的には、ある状況において実行されるメソッド。
主なマジックメソッド
constructとdestruct
__construct()
インスタンスの生成時に実行される
__destruct()
プロセスの終了時や、unset()で明示的にインスタンスを破棄した場合に実行される
getとset
__get()
アクセスできないプロパティにアクセスした場合に実行される
__set()
アクセスできないプロパティに対して値をセットした場合に実行される
issetとunset
__isset()
アクセスできないプロパティに対してisset()を行った場合に実行される
__unset()
アクセスできないプロパティに対してunset()を行った場合に実行される
isset()
変数が宣言されていて、NULLでなければ、true
NULLが代入されているか、変数が存在しない場合は、falseを返す。
isset(/*$変数名*/);
unset()
指定した変数を破棄する。
※あるグローバル変数を、ある関数の中でunset()した場合は、ローカル変数のみが破棄される。
unset(/*$変数名*/);
callとcallStatic
__call()
未定義のインスタンスメソッドを呼び出した場合に実行される
__callStatic()
未定義のクラスメソッドを呼び出した場合に実行される
sleep()とwakeup()
__sleep()
インスタンスをserializeする場合に実行される
__wakeup()
インスタンスをunserializeする場合に実行される
serialize() unserialize()とは
インスタンスをデータベースやファイルに保存したい場合、プロパティをそれぞれ保存して行くと、データが膨大になるため、
シリアライズ化することで、クラス内部の情報を文字列に変換して保存することが可能となる。
シリアライズ化した情報を再度生成したい場合は、アンシリアライズすることで再構築できる。
<?php
class Test
{
public $firstProperty = "プロパティ1";
public $secondProperty = "プロパティ2";
public function __sleep() //serialize()されたときに実行される
{
echo "シリアライズしました。\n";
return array('firstProperty', 'secondProperty');
}
public function __wakeup() //unserialize()されたときに実行される
{
echo "アンシリアライズしました。\n";
}
}
$test = new Test();
$serialized = serialize($test);
$unserialized = unserialize($serialized);
echo $unserialized->firstProperty . "\n";
echo $unserialized->secondProperty . "\n";
// 実行結果↓
// シリアライズしました。
// アンシリアライズしました。
// プロパティ1
// プロパティ2
toString
__toString()
インスタンスを文字列として扱いたい場合に利用できる
<?php
class Test
{
private $property = 'プロパティ';
public function __toString() {
return $this->property;
}
}
$test = new Test();
echo $test;
// 実行結果↓
// プロパティ
invoke
__invoke()
__invokeを実装したクラスを関数のように扱うことが可能になる
<?php
class Test
{
public function __invoke($params) {
print_r($params);
echo 'を受け取りました。';
}
}
$test = new Test();
//関数として利用(__invoke()が実行される)
$test('hoge');
// 実行結果↓
// hogeを受け取りました。
clone
__clone()
インスタンスがcloneされた場合に実行される
clone
インスタンスを複製することができる。
class Test
{
public $property = "オリジナル";
}
$test = new Test();
$test1 = $test; //インスタンスはポインタであり、代入では複製されない
$test1->property = "コピー"; //上記の理由から、$testも$test1も同じプロパティということになる
echo "original:" . $test->property;
echo "\ncopy:" . $test1->property . "\n";
// 実行結果↓
//original:コピー
//copy:コピー
<?php
class Test
{
public $property = "オリジナル";
}
$test = new Test();
$test1 = clone $test; //cloneでインスタンスを複製
$test1->property = "コピー";
echo "original:" . $test->property;
echo "\ncopy:" . $test1->property . "\n";
// 実行結果↓
//original:オリジナル
//copy:コピー
__clone()を使うケース
<?php
class Test
{
public $bar;
}
class Bar
{
public $val;
}
$test = new Test();
$test->bar = new Bar();
$test->bar->val = 'hoge';
$test1 = clone $test;
echo "\n before fuga";
echo "\n original:" . $test->bar->val;
echo "\n copy:" . $test1->bar->val . "\n";
$test1->bar->val = 'fuga';
echo "\n after fuga";
echo "\n original:" . $test->bar->val;
echo "\n copy:" . $test1->bar->val . "\n\n";
// 実行結果↓
// before fuga
// original:hoge
// copy:hoge
// after fuga
// original:fuga オリジナルにもfugaが代入されてしまう!
// copy:fuga
上記のプログラムでは、
①$testにTestインスタンスを代入
②$test(Testインスタンス)の$barにBarインスタンスを代入
③$test(Testインスタンス)の$bar(Barインスタンス)のvalに'hoge'を代入
④$test1に$testをcloneして代入
この時点での$testと$test1を見てみると...
# $test
object(Test)#1 (1) {
["bar"]=>
object(Bar)#2 (1) {
["val"]=>
string(4) "hoge"
}
}
# $test1
object(Test)#3 (1) { #cloneしたので、Testインスタンスは新しく生成(#3)されている。
["bar"]=>
object(Bar)#2 (1) { #$Barインスタンスは$testと同じもの(#2)を指している
["val"]=>
string(4) "hoge"
}
}
⑤$test1の$var->valに'fuga'を代入
$test1の$var->valは$testの$var->valと同じものを指すので、オリジナルもコピーも値が変更されてしまう。
上記は、__clone()を使うと解決できる
<?php
class Test
{
public $bar;
public function __clone() //cloneされた時に実行されるメソッドを追加
{
$this->bar = clone $this->bar;
}
}
//...省略...
// 実行結果↓
// before fuga
// original:hoge
// copy:hoge
// after fuga
// original:hoge オリジナルはそのまま!
// copy:fuga
# $test
object(Test)#1 (1) {
["bar"]=>
object(Bar)#2 (1) {
["val"]=>
string(4) "hoge"
}
}
# $test1
object(Test)#3 (1) {
["bar"]=>
object(Bar)#4 (1) { #新たなBarインスタンスがcloneされている!
["val"]=>
string(4) "fuga"
}
}