プログラミング

プログラミング初心者のPHP修羅の道#4〜PHP8上級問題を徹底追求する〜

この記事のキーワード

declare・error_reporting・整数型・コールバック関数・浮動小数点数・float型・NaN・bool型

PHP8上級資格取得へ向けたアウトプット記事になります。

PHP試験運営団体より公開されている模擬試験を1つ1つみていく形で事細かくみていきますが、勉強途中ゆえ間違っている部分に関してはご了承ください。

PHP上級資格のメイン教材はPHPマニュアルと指定されていますので、このマニュアルを主に踏襲した内容となっています。

主な勉強教材は以下になります。

1.独習PHP第4版

2.はじめてのPHP

 

3.PHP公式マニュアル

 

PHP8上級試験模擬問題

試験問題1

 

「PHPをインストールする」にあたっての一般的な注意事項のうち、誤っているものを1つ選びなさい。

 

選択肢①

 

PHPの最新のコードは、公式サイト https://www.php.net/ から、Downloads https://www.php.net/downloads に遷移すると、Changelogの確認を含めて取得できる。

公式マニュアルを確認するとChangelogの確認もできるため合っています。

選択肢②

 

PHPの「最新以外の(古い)コード」は、公式サイトでの提供は全くしていない。そのため、古いバージョンのコードが必要な場合、別途「非公式の外部サイト」からソースコードを入手する必要がある。

 

最新以外のコードも提供しているため誤りです。

選択肢③

 

ダウンロードできるソースコードの拡張子は「.tar.bz2」「.tar.gz」「.tar.xz」等があるが、解凍すれば中身のコードは同じものである。

 

選択肢①の画像よりダウンロードできる拡張子は確認でき、解凍後は中身のコードも同じため合っています。

選択肢④

 

Downloads https://www.php.net/downloads にはファイル指紋(sha256)がついているので、ダウンロードしたら、改竄の確認をするとよい。

 

問題文通りファイル指紋(sha256)がついているため合っています。

試験問題2

 

PHPの変数の型についての記述で、誤っているものを1つ選びなさい。
なお、すべてのコードの先頭には下記のコードが書かれているものとする。

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

下記はマニュアルから一部引用した内容である。

usort ( array &$array , callable $callback ) : bool

 

 

問題文について

 

declare(strict_types=1);

 

こちらのコードはあるコードブロックの中に 実行ディレクティブをセットするために使用し、挙動を指定することができます。

今回指定されている「strict_type=1」を指定することにより、型宣言に正確に対応する値のみを受け入れ、それ以外の値の場合TypeErrorがスローされます。

①厳密な型付けが有効になっていないファイルから、 厳密な型付けが有効になっているファイルで定義された関数を呼び出した場合は、 呼び出し側の好み(型の自動変換)が尊重され、値は型変換されます。

②厳密な型付けは、スカラー型の宣言に対してのみ定義されます。

③ディレクティブの値(今回は1)に変数や定数などは指定できずリテラルのみとなります。

 

<?php
// 以下は同じ意味です

// こうすることもできますし、
declare(strict_types=1) {
    // ここにすべてのスクリプトを書きます
}

// こうすることもできます
declare(strict_types=1);
// ここにすべてのスクリプトを書きます
?>

 

次にエラーについて解説します。

error_reporting(-1);

 

こちらのコードは出力する PHP エラーの種類を設定し、オプションのerror_levelを指定しなかった場合は、 error_reporting() は単に現在のエラーレベルを返します。

<?php

// 全てのエラー出力をオフにする
error_reporting(0);

// 単純な実行時エラーを表示する
error_reporting(E_ERROR | E_WARNING | E_PARSE);

// E_NOTICE を表示させるのもおすすめ(初期化されていない
// 変数、変数名のスペルミスなど…)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);

// E_NOTICE 以外の全てのエラーを表示する
error_reporting(E_ALL & ~E_NOTICE);

// 全ての PHP エラーを表示する
error_reporting(E_ALL);

// 全ての PHP エラーを表示する
error_reporting(-1);

// error_reporting(E_ALL); と同じ
ini_set('error_reporting', E_ALL);

?>

 

ちなみにエラーの重大度レベルは以下のようになります。

重大度レベル 概要
E_ERROR 1 致命的な実行時エラー(直ちにスクリプトを中断)
E_WARNING 2 警告(致命的でない)
E_PARSE 4 コンパイル時のエラー
E_NOTICE 8 注意

 

選択肢①

 

整数型(integer)は整数({..., -2, -1, 0, 1, 2, ...} という集合)を扱う。
整数のサイズはプラットフォームに依存するが、-2,147,483,6482,147,483,647 (32bit符号付) または -9,223,372,036,854,775,8089,223,372,036,854,775,807 (64bit符号付) である事が多い。
integer型の範囲外の数を指定した場合、floatとして解釈されるため、用途と環境によっては注意が必要である。

整数のサイズはプラットフォームに依存しますが、 約 20 億 (32 ビット符号付) が一般的な値です。 64 ビットプラットフォームでの通常の最大値は、およそ 9*10^18 (900京) になります。 

int型の範囲外の数を指定した場合又は結果がint型の範囲外の数となるような計算を行うと floatが代わりに返されます。

よって選択肢文は合っています。

選択肢②

 

コールバック (callback) はPHP 5.4 以降では callable タイプヒントと呼ばれていた。
これには、あらゆるビルドイン関数、ユーザ定義関数、メソッド、静的なクラスメソッドが指定できるが、言語構造 (例:echo  emptyisset 等) は指定が出来ない。
コールバックに「オブジェクトのメソッド」を指定する場合、 配列の 0 番目の要素にオブジェクトを、 そして 1 番目の要素にメソッド名を指定する必要がある。
静的なクラスメソッドを指定する場合は、配列の 0 番目の要素にクラス名を、1 番目の要素にメソッド名を指定する必要がある。或いは 'ClassName::methodName' という形式で指定してもよい。
コールバック (callback) が使われる関数には usort() 関数がある。

//そのため、以下のコード

class Hoge {
    public static function sort($a, $b) {
        return $a  $b;
    }
}

class Foo {
    public function sort($a, $b) {
        return $a  $b;
    }
}

$awk = [3, 1, 2];
usort($awk, [Hoge::class, 'sort']);
var_dump($awk);

$awk = [3, 1, 2];
usort($awk, 'Hoge::sort');
var_dump($awk);

$awk = [3, 1, 2];
usort($awk, [new Foo(), 'sort']);
var_dump($awk);

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

array(3) { 
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

選択肢文で説明されているコールバック関数についての説明は正しい記述ですが、より詳細に解説していきたいと思います。

コールバック関数とは「呼び出し先の関数でさらに呼び出される関数」のことで、単純な関数ユーザー定義関数オブジェクトのメソッドstaticメソッドであっても構いません。

以下はコールバック関数として使用できません。

・array()
・echo
・empty()
・eval()
・exit()
・isset()
・list()
・print
・unset()

protectedメソッドprivateメソッドは、クラスの内部からのみアクセス可能です。

そして、下記の関数は、ユーザーが定義するコールバック関数を引数として受け入れる関数として有名です。

call_user_func(配列, コールバック関数) 
usort(配列, コールバック関数) 

 

ここでusort()に関して触れておきます。

第1引数にソートしたい配列を指定、第2引数にユーザー定義関数を渡してソートすることができるため、ユーザーの思うようにソート可能なことからusortと名付けられています。

//ユーザー定義関数
sort($a,$b)

 

今回はsort()というユーザー定義関数があるため、「$a > $b」の場合並び順が入れ替わるため(1、2、3)という順番になります。

選択肢で記載されているsort()関数が何故このような処理にしているのかはよくわかりませんが、一般的にこのように使われています。

function sort($a, $b){
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

$a = array(3, 2, 5, 6, 1);
usort($a, "sort");

//宇宙演算子を使用した同じ意味のユーザー定義関数
//宇宙演算子は($a < $b)の場合-1を返す
function sort($a, $b){
    return $a <=> $b;
}

$a = array(3, 2, 5, 6, 1);
usort($a, "sort");

比較結果が等しくなる二つの要素があった場合、それらの並び順は保持されます。PHP 8.0.0 より前のバージョンでは、ソートした配列におけるそれらの並び順は不定でした。

次にコールバック関数についてです。

単純なコールバック関数の例は以下のようになります。

// コールバック関数の例
function my_callback_function() {
    echo 'hello world!';
}

//単純なコールバック
call_user_func('my_callback_function'); 

//出力:hello world

 

次にコールバックメソッドについて今回の選択肢の関数を引用しつつ確認してみます。

// コールバックメソッドの例
class Hoge {
    public static function sort($a, $b) {
        return $a  $b;
    }
}

class Foo {
    public function sort($a, $b) {
        return $a  $b;
    }
}

//全て同じ意味で、同じ出力結果になります。
$awk = [3, 1, 2];

// タイプ 2: staticメソッドのコール
usort($awk, [Hoge::class, 'sort']);
usort($awk, 'Hoge::sort');

// タイプ 3: オブジェクトメソッドのコール
usort($awk, [new Foo(), 'sort']);

 

よって選択肢のコード・出力結果は合っています。

選択肢③

 

浮動小数点数 (float / double) は、小数を扱う。
浮動小数点数には精度があり、PHP では通常 IEEE 754 倍精度フォーマットが使われる。
浮動小数点数はどうしても誤差を考慮する必要があるため、例えば「小数を直接比較して等しいかどうかを調べてはいけない」という事を理解する必要がある。
そのため、以下のコード

if (0.3 === (0.1 + 0.2)) {
    echo "=>ここにはならない";
} else {
    echo "=>こちらになる";
}

を実行すると「=>こちらになる」という結果が返る。

浮動小数点数の精度は有限のため、誤差が出てしまいます。

そのため、浮動小数点数を使って直接比較して等しいかどうかを調べてはいけません

よって、この選択肢は合っています。

ここでfloat型についてさらに深掘りしていこうと思います。

①文字列→float型への変換

・数値形式文字列は対応して変換
・それ以外は0に変換

②文字列以外→float型への変換

・int型に変換された後、float型に変換

nullは常に0に変換

④float型→整数型(int型,integer型)への変換

・変換するその数は0の方に丸められ、またPHP8.1.0以降ではこの暗黙的な変換は推奨されていないため警告が発生する。

var_dump((int)8.1); // PHP 8.1.0 より前でもあとでも「8」

補足ですが、NaN無限大intにキャストした結果は、常にゼロとなることもおさえておきます。

NaNとは?

数値でないことを示す特別なfloat型の値としてNANがあり、意味はNot a numberです。

以下はいずれもNaNが返されます。

//数学関数log()
var_dump(log( -1 )); //出力結果:float(NAN)

//数学関数sqrt():平方根
var_dump(sqrt( -4 )); //出力結果:float(NAN)

//数学関数acos():逆余弦(アークコサイン)[ラジアンで返す]
var_dump(acos(1.5)); //出力結果:float(NAN)

//無限大同士の計算
var_dump(INF - INF); //出力結果:float(NAN)

 //NaN同士の計算
var_dump(NAN * NAN); //出力結果:float(NAN)

 

平方根に関しては数学の世界では複素数(i)が存在するため、負数の平方根は以下のように表現でき、「±2」が答えとなりますが、PHPの関数においては複素数までは考慮されていないようです。

(±√ai)2 = -a → ±√4i = ±2

 

選択肢④

 

論理型 (boolean) は「真偽値」とも呼ばれ、値は、truefalsenull のいずれかになる。
なお、truefalsenull の文字は、大文字で書いても小文字で書いてもよい。

bool 型trueまたはfalseのどちらかの値だけを持ち真偽の値を表すためnullはありません。また、両方とも大文字小文字を区別しません。

よって、この選択肢が誤りとなります。

bool型への変換でfalseとなるもの

・booleanのfalse

・integerの0

・floatの0.0 or -0.0

・空の文字列「””」、文字列のゼロ「”0″」

・要素の数が0の配列

・Unit型のNull(初期化されてない変数)

ABOUT ME
ヒロ
社会人4年目/25歳/食品商社で2年間営業した後、IT業界にシステムエンジニアとして転職/Java,PHP言語を扱う開発エンジニア