3
1

More than 3 years have passed since last update.

PHP8以降の比較とmatch文について

Last updated at Posted at 2021-06-23

便利だけど使う前に挙動をしっかり理解しておきたいので。
予習メモです。

環境構築

PHP8の環境を用意します。
開発環境を汚したくない場合はDockerがおすすめです。

簡単なスクリプトならDockerfileを作成する必要もありません。
rmオプションを使用することにより、スクリプト実行後にコンテナが削除されます。

$ mkdir php8_test
$ cd php8_test
$ vi mytest.php
$ docker run -it --rm --name my-running-script -v "$PWD":/usr/src/php8_test -w /usr/src/php8_test php:8.0-cli php mytest.php 

公式ドキュメントにも紹介されています。

数値と文字列の比較

数値と文字列の比較について、文字列が数値形式か否かで変換の対象が変わります。

公式サイトより

数値形式の文字列と比較する場合は、PHP 8 は数値として比較を行います。それ以外の場合は、数値を文字列に変換し、文字列として比較を行います。

PHP7以前

'foobar'を数値に変換して比較します。
(int)'foobar'0なので、結果がtrueになってしまいます。

公式サイトより

文字列が 数値形式の文字列 の場合は、対応する整数値に解決されます。 そうでない場合は、ゼロ (0) に変換されます。

mytest.php
var_dump(0 == 'foobar');
//> bool(true)
var_dump(in_array(0, ['foobar']));
//> bool(true)

PHP8以降

'foobar'は数値形式の文字列ではないので、0を文字列に変換して比較します。
(string)0'0'なので、結果はfalseになります。

mytest.php
var_dump(0 == 'foobar');
//> bool(false)
var_dump(in_array(0, ['foobar']));
//> bool(false)

match式

PHP8から追加されたmatch式を紹介します。
「厳密な比較ができるswitch文」として利用できそうです。

公式サイトより

match 式は、値の一致をチェックした結果に基づいて評価結果を分岐します。 switch 文と似ていますが、 match 式は複数の候補と比較される制約式を持ちます。 switch 文とは異なり、 三項演算子のように値を評価します。 switch 文とは異なり、 弱い比較(==)ではなく、 型と値の一致チェック(===) に基づいて行われます。

$return_value = match (制約式) {
    単一の条件式 => 返却式,
    条件式1, 条件式2 => 返却式,
};

PHP7以前

ご存知のとおり、switch文では厳密な比較(===)が行われません。

mytest.php
$param = 1;

# switch文
switch ($param) {
    case '1':
        str_func();
        break;
    case 1:
        int_func();
        break;
    default:
        default_func();
}
//> Param is string!

function str_func()
{
    echo "Param is string!\n";
}

function int_func()
{
    echo "Param is integer!\n";
}

function default_func()
{
    echo "Default!\n";
}

そのため、条件分岐で厳密な比較を行う場合はif文三項演算子を利用する必要がありました。

mytest.php
# if文
if ($param === '1') {
    str_func();
} elseif ($param === 1) {
    int_func();
} else {
    default_func();
}
//> Param is integer!

# 三項演算子
$param === '1' ? str_func() : ($param === 1 ? int_func() : default_func());
//> Param is integer!

match式の使いどころ

「本当はswich文を使いたいけれど厳密な比較が出来ないから使えない・・・ぐぬぬ・・・」のような分岐が多い処理で役に立ちます。
下記コードのように$paramの種類ごとに処理が存在する場合は活躍できそうです。
また、記述できるのは一行の式だけですがbreak;が必要ないためコードがスッキリします。

mytest.php
match ($param) {
    '1' => str_func(),
    1, => int_func(),
    default => default_func(),
};
//> Param is integer!

逆に分岐が少ない場合はさほどメリットが無いかもしれません。

match式で厳密な比較を行わない方法

興味深い使い方もありました。

公式サイトより

制約式に true を指定することで、 厳密な一致チェックを行わずに match 式を使うことができます。

下記コードは制約式にtrueを指定しているため、条件式のin_array($param, $str_arr)の結果を元に条件分岐が行われます。
ですがin_arrayの第3引数にtrueが指定されていないので厳密な比較が実行されず、match式の結果にもそれが反映されてしまいます。

mytest.php
$param = 1;

$str_arr = ['1', '2'];
$int_arr = [1, 2];

//  制約式にtrueを指定
match (true) {
    in_array($param, $str_arr) => str_func(),
    in_array($param, $int_arr) => int_func(),
    default => default_func(),
};
//> Param is string!

この場合は条件式で厳密な比較を行う必要があります。

mytest.php
match (true) {
    in_array($param, $str_arr, true) => str_func(),
    in_array($param, $int_arr, true) => int_func(),
    default => default_func(),
};
//> Param is integer!

新しい機能は使いたくなるのが人の常ですが、使いどころは見極めていきたいです。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1