PHP

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

More than 1 year has passed since last update.


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