プログラミング

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

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

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

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

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

1.独習PHP第4版

2.はじめてのPHP

 

3.PHP公式マニュアル

 

PHP8上級試験模擬問題

試験問題26

 

関数に関する説明の中で、誤っているものを1つ選びなさい。
なお「¥」はバックスラッシュに読み替えること。

 

選択肢①

 

htmlentities() 関数と htmlspecialchars() 関数は、いずれも「文字を HTML エンティティに変換する」。
htmlspecialchars() 関数が「特殊文字」だけであるのに対し、htmlentities() 関数は「適用可能な全ての文字」を変換する。
この関数は、XSS対策のためのエスケープ処理としてよく使われている。XSS対策で使う場合、どちらを使ってもよい。

htmlentities( string $string , int $flags = ENT_COMPAT , string|null $encoding = null , bool $double_encode = true ) : string
htmlspecialchars( string $string , int $flags = ENT_COMPAT , string|null $encoding = null , bool $double_encode = true ) : string

ENT_COMPAT  ダブルクオートは変換しますがシングルクオートは変換しません。
ENT_QUOTES  シングルクオートとダブルクオートを共に変換します。
ENT_NOQUOTES  シングルクオートとダブルクオートは共に変換されません。

第二引数をデフォルトのままにすると「ダブルクオートは変換するがシングルクオートは変換しない」ので、XSS対策用には、第二引数を ENT_QUOTES にするとよい。

そのため、以下のコード

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

$string = '<>&"\'∞';
echo $string , "\n";
echo htmlspecialchars($string) , "\n";
echo htmlspecialchars($string, ENT_QUOTES) , "\n";
echo htmlentities($string, ENT_QUOTES) , "\n";

を実行すると、

<>&"'∞
<>&"'∞
<>&"'∞
<>&"'∞

となる。

 

htmlspecialchars()関数は、特殊文字(例: <, >, &, “など)を変換しますが、適用可能な全ての文字を変換するわけではありません。一方、htmlentities()関数はhtmlspecialchars()関数よりも広範囲にわたる文字を変換します。

よって出力は以下のようになります。

<>&"'∞
&lt;&gt;&amp;&quot;&#039;∞
&lt;&gt;&amp;&quot;&#039;∞
&lt;&gt;&amp;&quot;&#039;&infin;

 

htmlspecialchars()関数とhtmlentities()関数については過去の問題でも取り扱っていますので、参考までにご覧いただければと思います。

 

選択肢②

 

trim() 関数は文字列の先頭および末尾にあるホワイトスペースを取り除く。
また、 文字列の最初から空白 (もしくはその他の文字) を取り除くltrim() 関数、文字列の最後から空白 (もしくはその他の文字) を取り除くrtrim() 関数もある。

trim( string string,stringcharacters = " ¥n¥r¥t¥v¥0" ) : string
ltrim( string string,stringcharacters = " ¥n¥r¥t¥v¥0" ) : string
rtrim( string string,stringcharacters = " ¥n¥r¥t¥v¥0" ) : string

第二引数を指定しない場合は 0x20の空白、0x09のタブ、0x0Aのリターン などが削除されるが、引数を指定すると削除したい文字を指定する事も出来る。
そのため、以下のコード

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

$string="¥tab¥tc¥n";
var_dump(trim($string) );
var_dump( trim($string, "¥t¥n ac") );

を実行すると

string(5) "a b  c"
string(1) "b"

となる。

 

trim()関数は、文字列の先頭および末尾にあるホワイトスペース(空白、タブ、改行など)を取り除くための関数です。また、ltrim()関数は文字列の先頭から空白や指定した文字を取り除き、rtrim()関数は文字列の末尾から空白や指定した文字を取り除くための関数です。

これらの関数は、文字列の整形や入力データの正規化に使用されます。例えば、ユーザーの入力から取得した文字列を処理する際に、不要な先頭や末尾の空白を削除してデータの整合性を保つことができます。

第二引数を省略した場合、デフォルトで空白、タブ、改行などのホワイトスペースが削除されます。しかし、第二引数を指定することで、削除したい特定の文字をカスタマイズすることもできます

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

 

選択肢③

 

ord() 関数は、文字列の先頭バイトを、0 から 255 までの値に変換する。
またchr() 関数は、数値から、1バイトの文字列を生成する。

そのため、以下のコード

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

$s="abc";
$ascii = ord($s);
var_dump($ascii);
var_dump( chr($ascii));
$ascii += 5;
var_dump( chr($ascii) );

を実行すると

int(97)
string(1) "a"
string(1) "f"

となる。

 

ord()関数は、文字列の先頭バイトを0から255の範囲の値に変換します。先頭バイトが文字「a」のASCIIコードである97なので、$asciiの値は97になります。var_dump($ascii);によって、$asciiの値が表示されます。

一方で、97である$asciiに5を加えると102になります。ASCIIコード102は文字「f」に対応しているため、var_dump(chr($ascii));によって文字「f」が表示されます。

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

 

選択肢④

 

strpos() 関数は文字列内の部分文字列が最初に現れる場所を見つける。

strpos(string $haystack, string $needle , int $offset=0):int|false

文字列$haystackの中で、$needleが最初に現れる位置を探します。

返り値$needleが見つかった位置を、$haystack文字列の先頭($offsetの値とは無関係)からの相対位置で返します。

文字列の開始位置は0であり、1ではないことに注意しましょう。
$needleが見つからない場合はfalseを返します。

そのため、以下のコード

$fn = function($needle) {
    
    $string = "abc";
    
    if ( strpos($string, $needle) != false ) {
        echo "{$needle} が見つかりました\n";
    } else {
        echo "{$needle} は見つかりませんでした\n";
    }
};

$fn('a');
$fn('z');

を実行すると

a が見つかりました
z は見つかりませんでした

となる。

 

このコードは、strpos()関数を使用して文字列内で指定した部分文字列が最初に現れる位置を探し、その結果に基づいてメッセージを表示しています。

まず、$fnという無名関数(クロージャ)が定義されています。

無名関数は、特定の機能だけを定義したいという場合には、無名関数を利用することでスクリプトを読みやすくできます。また、引数の中に無名関数を記述したり、無名関数を変数に代入することができます。

詳しくは過去の記事でも取り扱っていますので、そちらをご覧ください。

この無名関数は、引数として部分文字列 $needle を受け取り、指定した文字列 $string の中で $needle が最初に現れる位置を探し、結果に応じてメッセージを表示します。

一見、文字列 'a' は文字列 'abc' の中に存在するため、strpos()関数は開始位置である0を返し、「aが見つかりました というメッセージが表示されるように思えますが、実際には「aが見つかりませんでした」と表示されてしまいます。

これは選択肢のコードで緩やかな比較を採用しているためです。

緩やかな比較では、「0 == false」はtrueとなってしまうため、意図していない挙動となってしまっています。

緩やかな比較に関しては以下の過去記事でも取り扱っています。

一方、文字列 'z' は文字列 'abc' の中に存在しないため、「zは見つかりませんでした 」というメッセージが表示されます。

よって、この選択肢は誤りです。

この関数は論理値 false を返す可能性がありますが、false として評価される値を返す可能性もあります。

 

試験問題27

 

関数に関する説明の中で、誤っているものを1つ選びなさい。
なお「¥」はバックスラッシュに読み替えること。

 

選択肢①

 

phar 拡張モジュールは、PHP アプリケーション全体をひとつの “phar” (PHP Archive) ファイルにまとめて配布やインストールを容易にするためのものである。
例えば、PHPで最近よく使われている Composer がPharで配布されている。
そのため、composer.pharの中は

#!/usr/bin/env php

という書き出しになっている。
また、中身がPHPファイルなので、ファイルに実行権限がなくても
php composer.phar
のコマンドラインで動かす事ができる。

 

PHP公式リファレンスより

Phar アーカイブは、複数のファイルをひとつにまとめるための便利な仕組みです。 Phar アーカイブを使用すれば、PHP のアプリケーションをひとつのファイルとして配布できるようになります。

また、それをディスク上に展開しなくてもそのまま実行できるのです。 さらに、他のファイルと同様に PHP から phar アーカイブを実行することができます。 コマンドラインとウェブサーバー経由のどちらでも実行可能です。

Phar アーカイブのもっとも一般的な使用法は、 完全なアプリケーションをひとつのファイルにまとめて配布することです

たとえば、PHP に同梱されている PEAR インストーラは phar アーカイブとして配布されています。 このような形式の phar アーカイブを使用するには、 コマンドラインあるいはウェブサーバーからアーカイブを実行します。

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

 

選択肢②

 

pharのスタブには __HALT_COMPILER() という関数が使われている。
__HALT_COMPILER() は「コンパイラの実行を中止する」関数である。この関数以降はコンパイルされる事がなく、インストール用ファイルのようなデータを PHP スクリプトに埋め込んでいる場合等に使われる。
そのため、以下のコード

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

echo "test¥n";
__HALT_COMPILER();
;
dummy data
hoge

を実行すると

Parse error: syntax error, unexpected identifier "data" in ...

となる。
しかし以下のコード

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

echo "test¥n";
__HALT_COMPILER();
;
dummy data;
hoge;

を実行すると

test

となる。

 

__HALT_COMPILER()は、いちばん外側のスコープでのみ使用可能です。

選択肢のコードではこの__HALT_COMPILER()以降はコンパイルが実行されないため、前者の場合も後者の場合も「test」のみが出力されます。

一方で、__HALT_COMPILER()をコメントアウトすると、選択肢のParse errorが出力されます。

よって、この選択肢は誤りです。

 

選択肢③

 

pharのファイルを作る場合は、Phar クラスを用いる。

public Phar::__construct( string $fname, int $flags = ?, string $alias = ?)

そのため、hoge.phpというファイル名で

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

class Hoge {
   private $i=999;
}

がある前提で、以下のコード

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

$obj = new Phar('./exam.phar');
$obj->addFile('hoge.php');

を実行するとexam.pharができあがる。
ただし php.ini の phar.readonly が0でない時は

Fatal error: Uncaught UnexpectedValueException: creating archive "./exam.phar" disabled by the php.ini setting phar.readonly in ...

となる。

 

pharファイルを作成する場合、Pharクラスを使用します。

Pharクラスのコンストラクタを呼び出すことで、pharファイルを作成します。

$fnameは作成するpharファイルの名前を指定します。また、$flags$aliasはオプションの引数であり、特定のフラグやエイリアスを設定するために使用されます。

選択肢のコードを実行すると、exam.pharというファイルが生成されます。ここでは、hoge.phpというファイルをexam.pharに追加しています。

ただし、php.iniファイルのphar.readonlyの設定が0でない場合、エラーが発生します。

このエラーは、phar.readonlyが有効になっているため、pharファイルの作成が制限されていることを示しています。

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

 

選択肢④

 

pharのファイルを使う場合には、Pharストリームラッパーを使う。
Pharストリームラッパーは phar:// から始まる。
そのため、先ほど作成した exam.phar がある前提で、以下のコード

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

require_once('phar://exam.phar/hoge.php');
$obj = new Hoge();
var_dump($obj);

を実行すると

object(Hoge)#1 (1) {
  ["i":"Hoge":private]=>
  int(999)
}

となる。

 

pharファイルを使用する場合、Pharストリームラッパーを利用します。Pharストリームラッパーは、phar://で始まる特殊なプロトコルを使用して、pharファイル内のリソースにアクセスします

先ほどの選択肢③で作成したexam.pharファイルがあると仮定すると、require_once('phar://exam.phar/hoge.php')の部分では、Pharストリームラッパーを使用してexam.phar内のhoge.phpファイルを読み込んでいます。

その結果、Hogeクラスが定義され、$objというオブジェクトが作成されます。その後、var_dump($obj)によって、オブジェクトの中身が表示されます。

Pharストリームラッパーを利用することで、pharファイル内のリソースを簡単に読み込んだり利用したりすることができます

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

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