Help us understand the problem. What is going on with this article?

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

More than 3 years have 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

nanapi
nanapiは、世の中のあらゆる「やり方」を世界一集めることを目指します。
http://nanapi.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away