このコーナーについて
私は根っからの文系なのでプログラミングや情報技術についてはITパスポート程度の知識しかなく、現在は全くの独学でコードや言語等のスキルの勉強はチュートリアル等でコードを書いて成果物を作りながら学んでいけるが、それらの過程で出てくる用語や技術についてはイマイチ学びきれない。
なので、折に触れて書籍及びQlita記事等のネットサーフィンで学んだ座学的知識をアウトプットすることがこのコーナーの目的である。
今回
パーフェクトPHPによるマジックメソッド
マジックメソッドとは
マジックメソッドとは実装すると、特定の条件を満たした場合自動的に呼び出されるメソッドであり、 __メソッド名
の形で表現される。
以前取り上げたconstruct
とdestruct
もこれの仲間である。
ドキュメントを見ると色々と種類があるが、別項で取り上げるオートロードで使うものを除くと以下のものを今回は読み解いていく。
sleep・wakeupメソッド
<?php
class TestSerialize {
private $score = 0;
private $subject = "";
public function __construct($score,$subject) {
$this->setScore($score);
$this->setSubject($subject);
}
public function setScore($score) {
$this->score = (int)filter_var($score);
}
public function setSubject($subject) {
$this->subject = (string)filter_var($subject);
}
public function getScore() {
return $this->score;
}
public function getSubject() {
return $this->subject;
}
public function __sleep() {
echo "シリアライズしました。"."\n";
return array("score","subject");
}
public function __wakeup() {
echo "アンシリアライズしました。"."\n";
}
}
$test = new TestSerialize(90,"数学");
echo $test->getScore()."\n";
echo $test->getSubject()."\n";
$serialized = serialize($test);
$unserialized = unserialize($serialized);
?>
serialize
はクラス内部の変数を一つの文字列に変換して保存しておく関数であり、unserialize
はその逆でシリアライズ化した情報を再度生成するための関数。
これらの関数を使うために実装しておくべきマジックメソッドがsleep
及びwakeup
メソッドであり、それぞれserialize・unserialize
関数をキーとして起動する。
前者は保存、後者は再構築の役割を持つ。
toStringメソッド
<?php
class TestClass {
public $foo;
public function __construct($foo) {
$this->foo = $foo;
}
public function __toString() {
return $this->foo;
}
}
$class = new TestClass("Hello");
echo $class;
?>
toStirng
メソッドはクラスを文字列として扱った場合をキーとして起動するマジックメソッドである。
この場合、インスタンス(オブジェクト)である$class
がecho $class;
という形で文字列として扱われたため、この場合$class
を何とecho
するかということをtoString
が決めているのである。
コードを見ると、return $this->foo;
となっている、そしてコンストラクタにより引数にインスタンス(オブジェクト)の引数に$foo
を指定して、その上で$this->foo = $foo;
と定義されているので
Hello
となる。
invokeメソッド
<?php
class CallableClass {
public function __invoke($x) {
var_dump($x);
}
}
$test = new CallableClass();
$test(5);
var_dump(is_callable(($test)));
?>
invoke
はクラスを関数として扱った場合をキーにして起動するマジックメソッドである。
invoke
メソッドに引数が与えられているので、それに従い$test
に5という引数を与えるとinvoke
メソッドで定義した処理が実行されるという仕組み。
is_callable()
は引数に指定した内容が関数としてコール可能かどうかを検証する関数である。すなわち、一連の実行結果は以下の通りになる。
int(5)
bool(true)
cloneメソッド
<?php
class Test {
public $bar;
public function __clone() {
$this->bar = clone $this->bar; // $thisー>barのコピーを作成。オリジナルは$testが、コピーは$test1が参照する。
}
}
class Bar {
public $val;
}
$test = new Test();
$test->bar = new Bar();
$test->bar->val = 'bar';
$test1 = clone $test;
echo '=baz前' . "\n";
echo "original:" . $test->bar->val . "\n";
echo "cloned:" . $test1->bar->val . "\n";
$test1->bar->val = 'baz';
echo '=baz後' . "\n";
echo "original:" . $test->bar->val . "\n";
echo "cloned:" . $test1->bar->val . "\n";
?>
clone
メソッドはクラスがclone
されることをキーにして起動するマジックメソッドである。
クラスのクローンに関してはクラスの基本の部分で学習した通り、同じクラスから複数のインスタンス(オブジェクト)を作る際に例えば$test=$test1
としてしまい、そこから各インスタンス(オブジェクト)を作成すると、それぞれのオブジェクトに因果関係が生まれ、1つのオブジェクトで変更された内容はすべてのオブジェクトで変更されてしまう。
なのでそれを嫌う場合は、インスタンスの単なるコピーを作ることでそれを回避しなければならない。
その際に利用されるのがclone
であり、その処理を具体的に定義するのがこのメソッドであると考えていい。
今回の場合は、$test
と$test1
で$val
の値を異なるものにしたいということになるので
Test
クラスの方にclone
メソッドを用意しておく。
あとは$test
でインスタンスを作り、さらにその中のbar
にアクセスしてさらにBar
クラスのインスタンスを作り、val
にアクセスしてbar
という値を代入する。
この時点でclone
すると、$test・$test1
ともにval=bar
である。
ここで、$test1->bar->val = 'baz';
と$test1
だけ別の値に変えてやる。
そうなると、$test1はval=baz
となるが、$tes
tは一見同じ$this->ba
rを参照しているように見えても、clone
メソッドによりそれはオリジナルを参照しているのか、そのコピーを参照しているのかという違いが生まれているので、$test
は変わらずval=bar
のままであるということになる。