• PHP
【php8上級/準上級試験】模擬問題解説 問題28 function_exists()

「第1回 PHP 8 上級 模擬試験」を解説していきます

本記事ではひたすら下記記事の模擬試験の解説をしていきたいと思います!

第1回 PHP 8 上級 模擬試験
https://study.prime-strategy.co.jp/study/ph8ex1/

解説記事一覧

模擬問題 28

関数 に関する説明の中で、誤っているものを1つ選びなさい。
また、すべてのコードには下記のコードが適切な箇所に書かれているものとする。

declare(strict_types=1);
error_reporting(-1);
下記はマニュアルから一部引用した内容である。

call_user_func ( callable $callback , mixed …$args ) : mixed
call_user_func_array ( callable $callback , array $args ) : mixed

forward_static_call ( callable $callback , mixed …$args ) : mixed
callback パラメータで指定したユーザー定義の関数あるいはメソッドを、 それに続く引数を指定してコールします。この関数はメソッドのコンテキストでコールしなければなりません。 クラスの外部で使用することはできません。 この関数は 遅延静的束縛 を使います。
forward_static_call_array ( callable $callback , array $args ) : mixed
callback パラメータで指定したユーザー定義の関数あるいはメソッドをコールします。 この関数はメソッドのコンテキストでコールしなければなりません。 クラスの外部で使用することはできません。 この関数は 遅延静的束縛 を使います。 転送先のメソッドへのすべての引数は値渡しで、 call_user_func_array() と同様に配列で指定します。

function_exists ( string $function_name ) : bool
組み込みの内部関数およびユーザー定義関数の中から、 function_name で指定した名前の関数を探します。

register_shutdown_function ( callable $callback , mixed …$args ) : void
スクリプト処理が完了したとき、あるいは exit() がコールされたときに実行するコールバック関数を登録します。
register_shutdown_function() は複数回コールする ことが可能で、登録された順に関数がコールされます。 登録した関数内で exit() をコールした場合、 処理はそこで終了してその他のシャットダウン関数はコールされません。

call_user_func() 関数 と call_user_func_array() 関数は、最初の引数で指定したコールバック関数をコールする。

call_user_func() 関数が「渡す引数を可変長引数で指定」するのに対して、call_user_func_array() 関数は「渡す引数を配列で指定」する。

第一引数に[オブジェクト, メソッド名]または[クラス名, メソッド名]の配列を渡すと、オブジェクトメソッドや静的メソッドを呼ぶ事も出来る。

また、引数を参照渡しで受け取る関数を call_user_func() から呼ぶと、エラー(Warning)が発生する。

そのため、以下のコード

function func($a, $b) {
    echo __FUNCTION__, PHP_EOL;
    var_dump($a, $b);
    echo PHP_EOL;
}

function func2(&$v) {
    $v[] = 999;
}

class Hoge {
    public function func1($a) {
        echo __METHOD__, PHP_EOL;
        var_dump($a);
        echo PHP_EOL;
    }

    public static function func2($a) {
        echo __METHOD__, PHP_EOL;
        var_dump(get_called_class(), $a);
        echo PHP_EOL;
    }
}

call_user_func('func', 1, 2);
call_user_func_array('func', ['var', 'val']);

$obj = new Hoge();
call_user_func([$obj, 'func1'], 999);
call_user_func([Hoge::class, 'func2'], 'val');

$v = [];
call_user_func('func2', $v);
var_dump($v);

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

func
int(1)
int(2)

func
string(3) "var"
string(3) "val"

Hoge::func1
int(999)

Hoge::func2
string(4) "Hoge"
string(3) "val"

Warning: func2(): Argument #1 ($v) must be passed by reference, value given in ...
array(0) {
}

問題文の内容は正しい⭕です

forward_static_call() 関数 と forward_static_call_array() 関数は、静的メソッドをコールする。

そのため、以下のコード

class Hoge {
    public static function func() {
        echo __METHOD__, PHP_EOL;
        var_dump(get_called_class());
        echo PHP_EOL;
    }
}

class Foo extends Hoge {
    public static function callMethod() {
        forward_static_call(['Hoge', 'func']);
        echo PHP_EOL;
        call_user_func(['Hoge', 'func']);
    }
}

Foo::callMethod();
forward_static_call(['Hoge', 'func']);

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

Hoge::func
string(3) “Foo”

Hoge::func
string(4) “Hoge”

Fatal error: Uncaught Error: Cannot call forward_static_call() when no class scope is active in …

よって選択肢の内容は正しい⭕です

function_exists() 関数 は指定した関数が定義されている場合に true を返す。

そのため、以下のコード

class Hoge {
    public function func() {
    }
}

function foo() {
}

$fn = function($v) {
    var_dump( $v, function_exists($v) );
    echo PHP_EOL;
};

$fn( [Hoge:class, 'func'] );
$fn( 'foo' );
$fn( 'function_exists' );
$fn( 'echo' );
$fn( 'dummy' );

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

array(2) {
  [0]=>
  string(4) "Hoge"
  [1]=>
  string(4) "func"
}
bool(true)

string(3) "foo"
bool(true)

string(15) "function_exists"
bool(true)

string(4) "echo"
bool(true)

string(5) "dummy"
bool(false)

function_exists() の仕様

function_exists(string $function_name): bool は、指定した関数が定義されている場合に true を返し、それ以外の場合は false を返す 関数です。

メソッド(クラスのメンバ関数)は対象外

よって問題文は誤り❌です

register_shutdown_function() 関数はシャットダウン時に実行する関数を登録する。

そのため、以下のコード

register_shutdown_function(function() {
    echo "register_shutdown_function 1", PHP_EOL;
});
register_shutdown_function(function($v) {
    echo "register_shutdown_function 2 {$v}", PHP_EOL;
}, 'val');
register_shutdown_function(function() {
    echo "register_shutdown_function 3", PHP_EOL;
    exit;
});
register_shutdown_function(function() {
    echo "register_shutdown_function 4", PHP_EOL;
});

echo "start", PHP_EOL;
exit;

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

start
register_shutdown_function 1
register_shutdown_function 2 val
register_shutdown_function 3

PHP strpos() 関数の動作 0 1 2 3 4 5 6 7 8 9 10 P H P P r o g r a m s 例1: strpos($string, ‘P’) 検索: ‘P’ 最初に見つかる位置: 0 (先頭) 例2: strpos($string, ‘P’, 1) 検索: ‘P’(インデックス1から検索開始) 見つかる位置: 2 (3番目の文字) 注意: if(strpos(…) == false) は先頭 (0) で誤判定!

この説明に誤りはありません。内容は⭕です

問題番号正解の選択肢
1PHPの「最新以外の(古い)コード」は、公式サイトでの提供は全くしていない。そのため、古いバージョンのコードが必要な場合、別途「非公式の外部サイト」からソースコードを入手する必要がある。
2論理型 (boolean) は「真偽値」とも呼ばれ、値は true か false か null のいずれかになる。なお、true、false、null の文字は、大文字でも小文字でもよい。
3抽象クラスから継承する際、親クラスで abstract としてマークされた全てのメソッドは子クラスで定義する必要があり、可視性は同等(またはより緩い制約)で、必須引数の数は同じであれば型宣言が異なってもかまわない。
4PHP において、デストラクタは __destruct() メソッドで実装される。親クラスのデストラクタは暗黙的に呼ばれ、呼び出し順序は「子クラスのデストラクタ → 親クラスのデストラクタ」となる。
5__get() はアクセス不能(protected または private)または存在しないプロパティからデータを読み込む際に使用される。なお、__getStatic() は存在せず、オブジェクトや静的コンテキストで動作しない。
6PHP のリファレンス渡しを使用すると、関数内で引数を修正できる。(※※正解テキストでは「呼び出す側で変数に & を付ける必要がある」と記載されています。)
7名前空間は namespace キーワードで宣言する。通常はファイルの先頭に記述する必要があり、名前空間宣言前に書かれたクラスはその名前空間に含まれない。
8PHP 5 では Exception クラスが全例外の基底クラスだったが、PHP 7 以降は Exception クラスは Throwable インタフェースを基底とし、Error クラスが内部エラーの基底クラスとして導入された。
9ArrayAccess インターフェイスは、オブジェクトを配列としてアクセスするための機能を提供する。
10SplFileInfo クラスは、ファイルの情報取得や操作を行うためのクラスである。
11$_COOKIE は、HTTP クッキーから渡された値が連想配列として格納され、また設定も可能である。
12PHP 7.1.x では、文字列操作関数で負のオフセット指定が可能となり、[] や {} による文字単位のアクセスも文字列の末尾からのオフセットとして解釈される。
13可変変数は、スーパーグローバル変数にも使用できる。
14PHP 7.4.x では、波括弧を使った配列や文字列のオフセットアクセスの文法は非推奨となった。
15PHP 8 では、private メソッドの継承に関するルールが変更され、親クラスの同名メソッドの可視性に関係なく子クラスでオーバーライド可能となった。
16break は、現在実行中の for, foreach, while, do-while, switch 構造の実行を終了し、オプションでネストしたループの何段分を抜けるか指定できる。
17XSS 対策として、htmlentities() を適切に使用することで、文字列や配列の入力に対して安全な出力が可能となる。
18アップロードされたファイルの元のファイル名は、$_FILES[‘{formのnameの値}’][‘name’] に格納され、move_uploaded_file() の第二引数として利用できる。
19uniqid() と mt_rand() を組み合わせることで、暗号論的にランダムな(推測困難な)トークンを生成できる。
20PHP のセッションでは、セッション ID がクッキーに保存され、session_set_cookie_params() によりそのクッキーのパラメータを設定できる。
21PHP の変数の参照カウントは、xdebug_debug_zval() で確認でき、オブジェクトを clone した場合は内部的に参照が使われ、一時的に参照カウントが増加する。
22DirectoryIterator クラスは、ディレクトリ内のファイルやサブディレクトリの情報を取得するシンプルなインターフェイスを提供する。
23mail() 関数は、メールを送信するための関数で、第四引数で追加のヘッダー情報を指定できる。
24escapeshellarg() と escapeshellcmd() は、外部入力をシェルコマンドの引数として使用する際に必要なエスケープ処理を行い、どちらを使用しても意味合いは同じである。
25stream_wrapper_register() 関数を使用すると、新しいストリームラッパー(プロトコルハンドラ)を登録できるが、既に存在する場合は失敗する。
26strpos() 関数は、文字列内で指定した部分文字列の最初の出現位置を返し、見つからなければ false を返す。ただし、先頭位置の場合は 0 が返るため注意が必要。
27Phar のスタブには __HALT_COMPILER() が使用され、これ以降のコードはコンパイルされない。
28function_exists() 関数は、指定された関数が定義されているかどうかをチェックし、存在すれば true を返す。
29openssl_decrypt() 関数は、openssl_encrypt() で暗号化されたデータを正しく復号し、元のデータを取り戻す。
30strtotime() 関数は、英語形式の日付文字列を Unix タイムスタンプに変換し、無効な日付の場合は false を返す。