LoginSignup
1
2

More than 3 years have passed since last update.

未経験からweb系プログラマーになるための独学履歴~マジックメソッド編~

Last updated at Posted at 2019-09-18

このコーナーについて

私は根っからの文系なのでプログラミングや情報技術についてはITパスポート程度の知識しかなく、現在は全くの独学でコードや言語等のスキルの勉強はチュートリアル等でコードを書いて成果物を作りながら学んでいけるが、それらの過程で出てくる用語や技術についてはイマイチ学びきれない。
なので、折に触れて書籍及びQlita記事等のネットサーフィンで学んだ座学的知識をアウトプットすることがこのコーナーの目的である。

今回

パーフェクトPHPによるマジックメソッド

マジックメソッドとは

マジックメソッドとは実装すると、特定の条件を満たした場合自動的に呼び出されるメソッドであり、 __メソッド名の形で表現される。
以前取り上げたconstructdestructもこれの仲間である。
ドキュメントを見ると色々と種類があるが、別項で取り上げるオートロードで使うものを除くと以下のものを今回は読み解いていく。

sleep・wakeupメソッド

serialize関数と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メソッド

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メソッドはクラスを文字列として扱った場合をキーとして起動するマジックメソッドである。
この場合、インスタンス(オブジェクト)である$classecho $class;という形で文字列として扱われたため、この場合$classを何とechoするかということをtoStringが決めているのである。

コードを見ると、return $this->foo;となっている、そしてコンストラクタにより引数にインスタンス(オブジェクト)の引数に$fooを指定して、その上で$this->foo = $foo;と定義されているので

出力結果
Hello

となる。

invokeメソッド

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メソッド

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となるが、$testは一見同じ$this->barを参照しているように見えても、cloneメソッドによりそれはオリジナルを参照しているのか、そのコピーを参照しているのかという違いが生まれているので、$testは変わらずval=barのままであるということになる。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2