39
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-07-28

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

39
29
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
39
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?