PHP7でタイプセーフなPHPを書きたい時

  • 11
    Like
  • 0
    Comment

PHP7

とりあえず動くPHPが大好きな皆さんこんにちは。
そんなゆるふわなPHPをタイプセーフ(型安全)に書けたらもっと好きになるのになーと思ったことはありませんか?僕はあります。

そんな熱い要望に応えた(と勝手に思っている)PHP7が正式にリリースされて、はや半年以上。
既に試されている方も多いと思いますが、PHPをもっと好きになるためにPHP7の三大新機能を使って、このたび僕もタイプセーフなPHPを書いてみましたので、その結果をまとめさせていただきます。

ちなみに、PHP7の三大新機能とは…

  • スカラー型宣言
    • int, string, bool がタイプヒンティングに使えるようになった。
  • 戻り値の型宣言
    • 引数と同様に関数の戻り値でも型宣言出来るようになった。
  • Null合体演算子
    • 三項演算子と isset() 地獄から解放される。 ?? と書く。

のことです。(僕が勝手に呼んでいる)

実験

いろいろ書いてみたので、順番に紹介させていただきます。
なお、PHPのバージョンは 7.0.7 です。

検証①

サンプルは英語、数学、国語の点数を合算して、合計点を表示するだけのプログラムです。
早速、書いてみます。

seven1.php
<?php

function calculate_total_score(array $scores): int
{
    $english = $scores['english'] ?? 0;
    $math = $scores['math'] ?? 0;
    $japanese = $scores['japanese'] ?? 0; 

    $totalScore = $english + $math + $japanese;
    return $totalScore;
}

$scores = array();
$scores['english'] = 70;
$scores['math'] = 80;
$scores['japanese'] = 60;

$totalScore = calculate_total_score($scores);

echo '合計点は' . $totalScore . 'でした。' . "\n";
実行結果
$ php seven1.php
合計点は210でした。

まず、関数の引数にスカラー型が利用出来るようになったので (array $scores) と書きます。
そして、関数の戻り値の型を指定するためには引数の後に : int と書きます。
これでタイプセーフなPHPが書けます!タイプセーフなPHPとか最強かよ!

検証②

では、ここで本当にタイプセーフなのか検証していきましょう。

seven2.php
<?php

function calculate_total_score(int $scores): int
{
    $english = $scores['english'] ?? 0;
    $math = $scores['math'] ?? 0;
    $japanese = $scores['japanese'] ?? 0;

    $totalScore = $english + $math + $japanese;

    return $totalScore;
}

$scores = array();
$scores['english'] = 70;
$scores['math'] = 80;
$scores['japanese'] = 60;

$totalScore = calculate_total_score($scores);

echo '合計点は' . $totalScore . 'でした。' . "\n";

引数の型指定を array から int に変更しました。
実行結果は以下です。

実行結果(抜粋)
$ php seven2.php
Fatal error: Uncaught TypeError: Argument 1 passed to calculate_total_score() must be of the type integer, array given

きちんとエラーになりました!PHP7最高かよ!

検証③

同じように戻り値も変えてみましょう。

seven3.php
<?php

function calculate_total_score(array $scores): array
{
    $english = $scores['english'] ?? 0;
    $math = $scores['math'] ?? 0;
    $japanese = $scores['japanese'] ?? 0;

    $totalScore = $english + $math + $japanese;

    return $totalScore;
}

$scores = array();
$scores['english'] = 70;
$scores['math'] = 80;
$scores['japanese'] = 60;

$totalScore = calculate_total_score($scores);

echo '合計点は' . $totalScore . 'でした。' . "\n";
実行結果(抜粋)
$ php seven3.php
Fatal error: Uncaught TypeError: Return value of calculate_total_score() must be of the type array, integer returned

ちゃんと怒られますね。やっぱりPHP7最高だわ。
これでめでたしめでたし…と思いきや…。

検証④

念のため、もう少し検証してみましょう。
検証③では戻り値の型指定をarray にしていましたが string にしてみましょう。

seven4.php
<?php

function calculate_total_score(array $scores): string
{
    $english = $scores['english'] ?? 0;
    $math = $scores['math'] ?? 0;
    $japanese = $scores['japanese'] ?? 0;

    $totalScore = $english + $math + $japanese;

    return $totalScore;
}

$scores = array();
$scores['english'] = 70;
$scores['math'] = 80;
$scores['japanese'] = 60;

$totalScore = calculate_total_score($scores);

echo '合計点は' . $totalScore . 'でした。' . "\n";

これを実行すると…

実行結果
$ php seven4.php
合計点は210でした。

/(^o^)\ナンテコッタイ
さすがPHPだぜ。。一筋縄ではいかない。でも、これぐらいならまだいいですよ。

検証⑤

では、戻り値の型指定を bool にしてみましょう。

seven5.php
<?php

function calculate_total_score(array $scores): bool
{
    $english = $scores['english'] ?? 0;
    $math = $scores['math'] ?? 0;
    $japanese = $scores['japanese'] ?? 0;

    $totalScore = $english + $math + $japanese;

    return $totalScore;
}

$scores = array();
$scores['english'] = 70;
$scores['math'] = 80;
$scores['japanese'] = 60;

$totalScore = calculate_total_score($scores);

echo '合計点は' . $totalScore . 'でした。' . "\n";

これを実行すると…

$ php seven5.php
合計点は1でした。

\(^o^)/オワタ
ちゃんと実行された上に1点になってしまいました。
もうPHPやだ。。Rubyしよ。。

検証⑥

PHPにタイプセーフは早かったのか…と半ば諦めながら、マニュアルを虚ろな目で眺めていると、こんな記述が。

スカラー 型宣言 には二つの方式があります。デフォルトの自動変換 (coercive) モードと、 厳密に判断する strict モードです。

なんだってー!!
もしかして strict モードにすればよいのでは??

ということでやってみました。

seven6.php
<?php
declare(strict_types=1);

function calculate_total_score(array $scores): bool
{
    $english = $scores['english'] ?? 0;
    $math = $scores['math'] ?? 0;
    $japanese = $scores['japanese'] ?? 0;

    $totalScore = $english + $math + $japanese;

    return $totalScore;
}

$scores = array();
$scores['english'] = 70;
$scores['math'] = 80;
$scores['japanese'] = 60;

$totalScore = calculate_total_score($scores);

echo '合計点は' . $totalScore . 'でした。' . "\n";

strict モードにするには declare(strict_types=1); と書きます。

これで実行すると、

実行結果(抜粋)
$ php seven6.php
PHP Fatal error:  Uncaught TypeError: Return value of calculate_total_score() must be of the type boolean, integer returned

キタ━━━━(゚∀゚)━━━━!!

ちゃんとエラーが出ました。

結論

  • PHPでタイプセーフなコードを書きたいときは strict モードにしましょう。
  • PHPのせいにせずちゃんとマニュアルを読みましょう(自戒)
  • PHP7最高!

参考サイト

『PHP: 新機能 - Manual』
http://php.net/manual/ja/migration70.new-features.php