[模擬問題] PHP8上級 – 言語リファレンス:マジックメソッド (CTO古庄道明からの出題)

こんにちは。PHP技術者認定機構 CTOの古庄道明です。
今日もPHP8上級試験の模擬問題と解説を紹介します。
以下を解いて出題のイメージと知識を補っていただけると幸いです。

目次

問題

メソッドに関する説明の中で、誤っているものを1つ選びなさい。
なお、すべてのコードの先頭には下記のコードが書かれているものとする。
declare(strict_types=1);
error_reporting(-1);

選択肢

選択肢1
PHP において、コンストラクタは、__construct() メソッドで実装される。
そのため、以下のコード

class Hoge {
    public function __construct() {
        echo __METHOD__, PHP_EOL;
    }
}
$obj = new Hoge();

は正しく実行でき、結果は Hoge::__construct となる。
なお、コンストラクタを有している場合、親クラスのコンストラクタが暗黙の内にコールされることはない。
そのため、以下のコード

class Hoge {
    public function __construct() {
        echo __METHOD__, PHP_EOL;
    }
}

class Foo extends Hoge{
    public function __construct() {
        echo __METHOD__, PHP_EOL;
    }
}

$obj = new Foo();

を実行すると、結果は Foo::__construct となる。
親クラスのコンストラクタを実装する場合には、parent::をコールする事が必要となる。
そのため、以下のコード

class Hoge {
    public function __construct() {
        echo __METHOD__, PHP_EOL;
    }
}

class Foo extends Hoge{
    public function __construct() {
        parent::__construct();
        echo __METHOD__, PHP_EOL;
    }
}

$obj = new Foo();

を実行すると、結果は次のとおりとなる。

Hoge::__construct
Foo::__construct

選択肢2

PHP において、デストラクタは、__destruct() メソッドで実装される。
そのため、以下のコード

class Hoge {
    public function __destruct() {
        echo __METHOD__, PHP_EOL;
    }
}

$obj = new Hoge();

は正しく実行でき、結果は Hoge::__destruct となる。
なお、デストラクタを有している場合、親クラスのデストラクタは、暗黙の内にコールされる。コールされる順番は「子クラスのデストラクタ → 親クラスのデストラクタ」の順番である。
そのため、以下のコード

class Hoge {
    public function __destruct() {
        echo __METHOD__, PHP_EOL;
    }
}

class Foo extends Hoge{
    public function __destruct() {
        echo __METHOD__, PHP_EOL;
    }
}

$obj = new Foo();

を実行すると、結果は次のとおりとなる。

Foo::__destruct
Hoge::__destruct

選択肢3

__call() マジックメソッドを使うと「アクセス不能なメソッドがオブジェクトのコンテキストで呼び出された時」に、処理を入れる事ができる。
そのため、以下のコード

class Hoge {
    public function __call(string $name, array $arguments) {
        echo "call: {$name}", PHP_EOL;
        var_dump($arguments);
        echo PHP_EOL;
    }
}

$obj = new Hoge();
$obj->test();
$obj->test2(1, '2', [3]);

は正しく実行でき、結果は次のとおりとなる。

call: test
array(0) {
}

call: test2
array(3) {
  [0]=>
  int(1)
  [1]=>
  string(1) "2"
  [2]=>
  array(1) {
    [0]=>
    int(3)
  }
}

回答と解説

選択肢1はコンストラクタの設問です。

コンストラクタとは「クラスからインスタンスを生成するタイミングで呼び出される処理」です。
PHPであれば

$インスタンス = new クラス名();

の処理のタイミングで呼び出される処理、ということになります。

PHPのコンストラクタは、古くは「クラス名と同じ名前のメソッド」だったのですが、PHP5で __construct() マジックメソッドが登場、PHP7で非推奨扱い(E_DEPRECATED が発生する)、PHP8以降は「クラス名と同じ名前のメソッドは、コンストラクタと解釈されなくなりました」となります。

また、これはコンストラクタに限りませんが、PHPであらゆるオーバーライド(上書き)されたメソッドは、「暗黙のうちに親クラスの同一名のメソッドを呼び出すことはありません」。
オーバーライド(上書き)されたメソッドで、オーバーライドされた元のメソッド(今回の設問ですと、親クラスの __construct() メソッドを呼び出す時は、明示的に parent:: でアクセスをします。

そのため、選択肢1に書かれている3つのコードは、いずれも書かれている通り、正しく動きます。
実務では日常的に使われるものなので、しっかり押さえておきましょう。

選択肢2はデストラクタの設問です。

デストラクタとは「インスタンスが削除されるタイミングで呼び出される処理」です。
PHPでは、インスタンスを参照するリファレンスがひとつもなくなったときに呼び出されます。あるいは、スクリプトの終了時にも順不同で呼び出されます。

PHPのデストラクタは、PHP4では実装されておらず、PHP5になってから実装されました。そのため、古いスタイルのデストラクタ(コンストラクタだと「クラス名と同じメソッド名」に相当するもの)は、存在しません。
__destruct() マジックメソッドを使うことで、PHPではデストラクタを実装することができます。

コンストラクタのところにも書きましたが、PHPのあらゆるオーバーライド(上書き)されたメソッドは、「暗黙のうちに親クラスの同一名のメソッドを呼び出すことはありません」。
また、デストラクタも、コンストラクタと同様、明示的にparent::を使うことで、親クラスの「オーバーライドされた元のメソッド」を呼び出すことができます。

そのため、選択肢2のうち、1番目のコードは正しく動きますが、2番目のコードは「parent::__destruct()」が書かれていないため、書かれているような動きはしません。
もし「選択肢2の実行結果」のように動かしたい場合、以下のコードである必要があります。

class Hoge {
    public function __destruct() {
        echo __METHOD__, PHP_EOL;
    }
}

class Foo extends Hoge{
    public function __destruct() {
        echo __METHOD__, PHP_EOL;
        parent::__destruct(); // <- ここを追加
    }
}

$obj = new Foo();

実務で出番は少なめですが、必要な場面では便利なので知っておくとよいでしょう。

選択肢3は__call() マジックメソッドの設問です。

マジックメソッドは「ある動作がオブジェクトに対して行われた場合に、 PHP のデフォルトの動作を上書きする特別なメソッド」です。
選択肢1と2のコンストラクタ、デストラクタも、(PHPでは)マジックメソッドです。

__call() マジックメソッドは「アクセス不能メソッドをオブジェクトのコンテキストで実行したときに起動します」。端的には「存在しない、あるいはアクセス権の制約で呼び出せないメソッドを、$インスタンス->メソッド() の形で呼び出した時」に__call()が呼び出されます。
第一引数には「どんなメソッド名で呼び出そうとしたか」、第二引数に「呼び出した時にメソッドに渡した引数の配列」が入ります。

そのため、選択肢3に書かれているコードは、書かれている通り、正しく動きます。
実務では業務ロジックよりもライブラリやフレームワークの中でよく使われます。まずは「自分で書けなくても、出てきたコードを読んで理解できる」レベルを目指しておきましょう。

選択肢2に誤りがあるため、解答は2になります。

PHP8上級試験と公式問題集に興味がある方は、以下のページをご覧のうえ、この機会に是非受験ください。

PHP8上級試験
https://www.phpexam.jp/summary/expert8

公式問題集:PHP8技術者認定上級試験公式問題集上巻
https://www.amazon.co.jp/dp/B0FQ1LTTQ4/

公式問題集:PHP8技術者認定上級試験公式問題集下巻ベータ
https://www.amazon.co.jp/dp/B0F7F4H8FP/

また、試験対策セミナーは毎月開催しています。興味がある方は以下のページをご覧いただき是非セミナーにもご参加ください。(フォローいただけるとセミナーのご案内が届くようになります)

PHP技術者認定機構の公式Peatixグループ
https://peatix.com/group/43424
www.phpexam.jp

この記事が気に入ったら
いいね または フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次