【やさしく解説】PHP8上級試験の模擬問題(5)

PHP
スポンサーリンク

PHP8 上級/準上級試験の認定模擬問題として、プライム・ストラテジー様のPRIME STUDYが認定されているようです。ただ、この模擬問題には解説がありませんので解説をまとめていこうと思います。シリーズ第5回目です。

PHP初級レベルから脱却して中級/上級レベルにいきたい人にピッタリの内容ですね。

PRIME STUDY認定模擬問題のリンクはこちらです → https://study.prime-strategy.co.jp/ 

問題文

メソッドに関する説明の中で、誤っているものを1つ選びなさい。
なお「\」はバックスラッシュに読み替えること。
また、すべてのコードの先頭には下記のコードが書かれているものとする。

declare(strict_types=1);
error_reporting(-1);

(1)
__toString() メソッドにより、クラスが文字列に変換される際の動作を決めることができる。
そのため、以下のコード

class Hoge {
  public function __toString() {
    return $this->s;
  }

  private $s = 'string';

}

$obj = new Hoge();
echo 'object: ' . $obj , PHP_EOL;


は正しく実行でき、結果は object: string となる。

また、__toString() メソッドで例外を投げる事は、PHP 7.3 までは出来なかったが、PHP 7.4 からは出来るようになった。
そのため、以下のコード

class Hoge {
  public function __toString() {
    throw new \Exception('*** test string ***');
  }

  private $s = 'string';
}

try {
  $obj = new Hoge();
  echo 'object: ' . $obj, PHP_EOL;
} catch(\Throwable $e) {
  echo $e->getMessage(), PHP_EOL;
}

を実行すると

*** test string ***

となる。

(2)
__invoke() メソッドは、 スクリプトがオブジェクトを関数としてコールしようとした際にコールされる。
そのため、以下のコード

class Hoge {
  public function __invoke() {
    var_dump($this);
    return 'string';
  }
}

$obj = new Hoge();
$r = $obj();
var_dump($r);


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

object(Hoge)#1 (0) {
}
string(6) "string"

(3)
__get() は、アクセス不能 (protected または private) または存在しないプロパティからデータを読み込む際に使用する。
__getStatic() は存在せず、オブジェクトのコンテキスト、静的コンテキストのどちらでも動く。
そのため、以下のコード

class Hoge {
  public function __get(string $name) {
    return "not exist {$name}";
  }
}

$obj = new Hoge();
echo $obj->test, PHP_EOL;
echo Hoge::$test2, PHP_EOL;


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

not exist test
not exist test2

(4)
__debugInfo() メソッドが実装されていると、var_dump() でオブジェクトをダンプするときに出力するプロパティの情報を制御できる。
そのため、以下のコード

class Hoge {
  public function __debugInfo() {
    return [
    's' => $this->s,
    'i' => $this->i,
    ];
  }

  private $pass = 'password';
  private $s = 'string';
  private $i = 999;
}

$obj = new Hoge();
var_dump($obj);


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

object(Hoge)#1 (2) {
  ["s"]=>
  string(6) "string"
  ["i"]=>
  int(999)
}

解説

選択肢1

正しいです。
__toString() メソッドによりクラスが文字列に変換される際の動作を定義できます。また、PHP 7.4 以降では例外をスローすることも可能です。

順を追ってみていきましょう。
__toString() は、オブジェクトが文字列として扱われるときの振る舞いを決める特別なメソッドです。たとえば、通常はオブジェクトを echo で出力しようとするとエラーになります。ですが、__toString() を定義すると、オブジェクトを文字列に変換できるようになります。

1つ目のコードを見ていきます。
(1~2行目)まず、クラス Hoge には __toString() が定義されています。
(3行目)次に、__toString() の中では、$this->s を返しています。
(6行目)$s は ‘string’ という値を持っています。
(11行目)echo ‘object: ‘ . $obj の部分で、オブジェクトを文字列として出力しようとしたため、 __toString() が実行され、$s の値 ‘string’ が返されます。その結果、「object: string」が出力されます。

次に2つ目のコードです。
PHP 7.3 までは __toString() の中で例外(エラー)を投げることができませんでしたが、PHP 7.4 からは可能になりました。
(3行目)クラス Hoge の __toString() メソッドは、throw new \Exception(‘*** test string ***’); によって例外を投げます。
(11行目)echo ‘object: ‘ . $obj を実行すると __toString() が呼ばれ、例外が発生します。
(9~14行目)例外が発生すると、 try { … } catch (\Throwable $e) { … } の catch に処理が移り、$e->getMessage() を出力します。 getMessage() の内容は *** test string *** なので、最終的に *** test string *** が出力されます。

選択肢2

正しいです。
__invoke() は、オブジェクトを 関数のように呼び出したときに実行される特別なメソッドです。
通常、オブジェクトをそのまま () をつけて実行しようとするとエラーになりますが、__invoke() を定義すると、その中で必要な処理を書くことができます。

コードを追っていきましょう。
(2~4行目)まず、Hoge クラスを作成。 __invoke() メソッドを定義しています。var_dump($this); で自分自身($this)を表示した後、’string’ という文字列をreturnしています。
(8~10行目)Hogeクラスをnewしたあと、オブジェクトを関数のように呼び出します。$obj(); のように () をつけて呼び出しています。すると、__invoke() が自動的に実行されます。
これにより、var_dump($this); が実行され、自分自身(Hoge のオブジェクト)が表示されます。また、’string’ を返すので、それが $r に代入されます。最後に、$r の値(’string’)を var_dump() で表示します。

選択肢3

誤っています。
__get() は、存在しないプロパティ や アクセスできないプロパティ(private / protected) にアクセスしようとしたときに自動的に呼び出されます。

コードを見ていきましょう。
Hoge クラスには test というプロパティはありません。ですが、 $obj->test にアクセスすると、__get(‘test’) が自動的に呼ばれ、 “not exist test” という文字列を返します。
__get() は インスタンスのプロパティ にアクセスしたときのみ呼ばれます。静的プロパティ (Hoge::$test2) に対しては動作せず、エラーとなります。

PHPには __getStatic() というメソッドは存在しません。もし静的なプロパティアクセス (Hoge::$test2) に対して似た動作をさせたい場合は、代替として__callStatic() を使いましょう。


選択肢4

正しいです。
__debugInfo() は、var_dump() を使ってオブジェクトを出力するときに、表示されるプロパティの情報をカスタマイズできる 特殊なメソッド(マジックメソッド)です。

順を追って解説していきます。
PHP で var_dump($obj) を実行すると、オブジェクト内のすべてのプロパティ(public / protected / private) が表示されます。例えば、次のようなクラスを考えます。

class Hoge {
  private $pass = 'password';
  private $s = 'string';
  private $i = 999;
}
$obj = new Hoge();
var_dump($obj);

この場合、通常は以下のような出力になります。

object(Hoge)#1 (3) {
  ["pass":"Hoge":private]=>
  string(8) "password"
  ["s":"Hoge":private]=>
  string(6) "string"
  ["i":"Hoge":private]=>
  int(999)
}

private なプロパティ pass, s, i もすべて var_dump() によって表示されてしまいます。ですが、pass にはパスワードのような 機密情報 が含まれているため、ログやデバッグ時に表示されると セキュリティリスク になることがあります。

__debugInfo() を実装するとどうなるか?
__debugInfo() を定義すると、var_dump() で表示する情報を制御できる ようになります。
以下のコードを見てみましょう。

class Hoge {
  public function __debugInfo() {
    return [
      's' => $this->s,
      'i' => $this->i,
    ];
  }
  private $pass = 'password';
  private $s = 'string';
  private $i = 999;
}
$obj = new Hoge();
var_dump($obj);

このコードを実行すると、出力は次のようになります。

object(Hoge)#1 (2) {
  ["s"]=>
  string(6) "string"
  ["i"]=>
  int(999)
}

pass が var_dump() の出力から 除外され、 代わりに、s と i だけが表示されています。
このように、__debugInfo() メソッドを実装すると、var_dump() の出力をカスタマイズできます。

正解選択肢

以上より選択肢3が正解となります。

他の問題へ

コメント

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