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

PHP初級レベルから脱却して中級/上級レベルにいきたい人にピッタリの内容ですね。
PRIME STUDY認定模擬問題のリンクはこちらです → https://study.prime-strategy.co.jp/
問題文
クラスに関する説明の中で、誤っているものを1つ選びなさい。
なお「\」はバックスラッシュに読み替えること。
また、すべてのコードの先頭には下記のコードが書かれているものとする。
declare(strict_types=1);
error_reporting(-1);
(1)
三つの特別なキーワード self と parent そして static がクラス定義の内部からプロパティまたはメソッドにアクセスする際に使用される。
そのため、以下のコード
class Hoge {
public function test_1() {
echo __METHOD__, PHP_EOL;
}
public static function testStatic() {
echo __METHOD__, PHP_EOL;
}
public static function staticCall() {
self::testStatic();
static::testStatic();
}
}
class Foo extends Hoge {
public function test_1() {
parent::test_1();
echo __METHOD__, PHP_EOL;
}
public static function testStatic() {
echo __METHOD__, PHP_EOL;
}
}
$obj = new Foo();
$obj->test_1();
Foo::staticCall();
を実行すると、結果は次のとおりとなる。
Hoge::test_1
Foo::test_1
Hoge::testStatic
Foo::testStatic
(2)
static メソッドはオブジェクトのインスタンスを生成せずにコールするため、疑似変数 $this は、 static として宣言されたメソッドの内部から利用することはできない。
そのため、以下のコード
class Hoge {
public static function test() {
var_dump($this);
}
}
Hoge::test();
を実行すると、結果は次のとおりとなる。
Fatal error: Uncaught Error: Using $this when not in object context in …
(3)
static プロパティは、アロー演算子 -> によりオブジェクトからアクセス することはできない。
そのため、以下のコード
class Hoge {
static $i = 100;
public function test() {
echo $this->i;
}
}
$obj = new Hoge();
$obj->test();
を実行すると、結果は次のとおりとなる。
Notice: Accessing static property Hoge::$i as non static in …
Warning: Undefined property: Hoge::$i in …
(4)
抽象クラスから継承する際、親クラスの宣言で abstract としてマークされた全てのメソッドは、子クラスで定義されなければならない。
また、これらのメソッドは同等 (あるいはより緩い制約) の可視性で定義される必要がある。
一方でメソッドのシグネチャ (引数の型と順番) については、必須引数の数は同じである必要があるが、型宣言は異なってもかまわない。
そのため、以下のコード
abstract class Hoge {
abstract public function __construct(string $s, array $a);
protected $s;
protected $a;
}
class Foo extends Hoge {
public function __construct(string $s, \arrayObject $a) {
$this->s = $s;
$this->a = $a;
}
}
$obj = new Foo('', new \arrayObject());
var_dump($obj);
は正しく実行でき、結果は次のとおりとなる。
object(Foo)#1 (2) {
["s":protected]=>
string(0) ""
["a":protected]=>
object(ArrayObject)#2 (1) {
["storage":"ArrayObject":private]=>
array(0) {
}
}
}
解説
選択肢1
正しいです。
self、parent、static の挙動についての理解が問われる問題です。
18行目「parent::test_1();」は親クラスのメソッドを呼びます。11行目「self::testStatic();」は定義時点のクラス(Hoge)を基準として呼びます。12行目「static::testStatic();」は実行時のクラス基準(Foo)で呼びます。これを「遅延静的束縛」と呼びます。
このポイント3点を押さえてコードを追うと、実行結果のようになることがわかるかと思います。
選択肢2
正しいです。
このコードは クラスメソッド(static メソッド)内で $thisを使おうとしているため、エラーが発生します。$thisは「現在のオブジェクト(インスタンス)を指す特殊な変数」です。staticメソッド内では インスタンスが存在しないため、$thisを使うことはできません。
選択肢3
正しいです。
staticプロパティは クラスに属する変数 であり、通常のインスタンス変数とは異なります。問題では$this->i を使って $i にアクセスしようとしていますが、$thisは「インスタンスのプロパティ」を指すため、クラスの static プロパティにはアクセスできません。
クラス内からであれば、staticプロパティには 「self::$i 」という書き方でアクセスできます。また、クラス外からであれば、「Hoge::$i」という書き方でstaticプロパティへアクセスできます。
ちなみに「->」はアロー演算子、「::」はスコープ演算子などと呼ばれます。
選択肢4
誤っています。
抽象クラスのメソッドをオーバーライドする際、親クラスの抽象メソッドのシグネチャ(引数の型宣言や順番) は、子クラスで完全に一致する必要があります。特に、型宣言が異なる場合はエラーになります。
記述の中で「型宣言は異なってもかまわない」とされていますが、これは誤りです。
正解選択肢
以上より選択肢4が正解となります。
コメント