sekaie engineers' blog

セカイエ株式会社が主催するエンジニア勉強会について

セブン!!

好きなウルトラマンはゼロです。大西です。
ゼロかっこいいですよね。セブンの息子だし!

はじめまして、セカイエで主にバックエンドエンジニアをやっています。
今回は社内勉強会で話した「PHP7」について紹介したいと思います。

PHP7について

f:id:sekaie:20151111184018p:plain

ご存知の人もいるかと思いますが、PHPが約10年ぶりにメジャーバージョンアップをします!!

弊社システムもPHPで実装しているということで、とても注目しているPHP7ですが、

  • どんな新機能が!?
  • PHP7って速いらしいよ!!?
  • (うちのシステムは)移行できるのか!???( ゚д゚ )クワッ!!

といったことを、調査しましたのでご紹介します。

どんな新機能が!?

ここではPHP7で実装された新機能の一部を紹介します。

新機能その1:致命的エラーを例外として拾えるようになった

これまで
「致命的エラーが発生してプログラムが終了」
していたものを
例外としてキャッチしてプログラムを終了させない
ように出来ます。

こんな感じ

<?php

function hoge($obj) {
    $obj->method();
}
try {
    hoge(null);
} catch(Error $e) {
    echo "Error : " . $e->getMessage();
}

気づいた人もいると思いますが、catch してるオブジェクトの型が「Exception」ではなく「Error」となってます。
致命的エラーは「Error」を throw するよう変更されています。
ちなみに今ままでの例外は変わらず「Exception」を throw しますので、これまでのコードはそのまま使えます。

いつ使うねん!?って感じですが、例えば
テストで致命的エラーを発生させるときにテストを終了させないようにしたり、
このあと紹介する「関数の引数の型宣言」で宣言した型以外を引数にセットした時に、例外を投げる事が出来ます。

この機能についてもっと詳しく知りたい方はこちらを参照してください。

PHP: PHP 7 でのエラー - Manual

PHP: rfc:throwable-interface

新機能その2:関数の引数にスカラー型の型宣言ができる!

関数の引数にスカラー型を指定することが出来るようになりました。

こんな感じ。

<?php

function addition(int $a, int $b) {
    return $a + $b;
}
echo "1 + 2 = " . addition(1, 2);

# 1 + 2 = 3

また、指定した型以外を引数にセットした場合、
これまでは致命的エラーが発生していたのですが、新機能1で紹介した通り例外を throw するようになります。

こんな感じ。

<?php

function addition(int $a, int $b) {
    return $a + $b;
}

try {
    echo "1 + 2 =" . addition(1, "aaa");
} catch(TypeError $e) {
    echo "Error : " . $e->getMessage();
}

# Error : Argument 2 passed to addition() must be of the type integer, string given

詳しくはこちら。

PHP: 関数の引数 - Manual

新機能その3:関数の戻り値に型宣言できる!

「新機能その2」と似た機能ですが、返り値にも型宣言を設定することが出来ます。

こんな感じ。

<?php

function addition($a, $b): int {
    return $a + $b;
}
echo "1 + 2 = " . addition(1, 2);

# 1 + 2 = 3

また、こちらも「新機能2」と同様に指定した型以外の返り値で返した時は「TypeError」を throw します。

こんな感じ。

<?php

function addition($a, $b): int {
    return "hoge";
}
try {
    echo "1 + 2 = " . addition(1, 2);
} catch(TypeError $e) {
    echo "Error : " . $e->getMessage();
}

# Error : Return value of addition() must be of the type integer, string returned

詳しくはこちら。

PHP: 返り値 - Manual

新機能その4:「??」演算子の追加

<?php

$data = isset($_POST['data']) ? $_POST['data'] : array();

PHPを書いたことある人ならこんなコードを書いたことがあるんじゃないでしょうか?
これをすっきり記述できるようになるのが「??」演算子です。

<?php

$data = $_POST['data'] ?? array();

短いっ!!

null でなかったらその値、null なら右オペランドの値を返すようになっています。
また、この演算子は isset と同じように未定義値にも利用することが出来ます。

紹介したのはほんの一部です

今回紹介した機能は、追加された新機能の内ほんの一部です。
詳しくは、マニュアルや、RFCの一覧を見てみると良いと思います。

PHP: rfc

PHP: PHP マニュアル - Manual

PHP7って速いらしいよ!!?

今回のバージョンアップで、アプリケーションによりますがPHP5.6の2倍以上の速度改善があるようです。

f:id:sekaie:20151117204637p:plain

参考:http://talks.php.net/tokyo15#/

これだけ見ても、PHP7使ってみたくなりますよね!!?

性能改善を実現するために、変数や配列の内部構造を変更してメモリ使用量の削減、データの局所性が改善されたりしているそうです。
特に「配列」の改善は、メモリ使用量が劇的に減っています。

こうゆうのを見ると、うちのシステムをPHP7に移行すると速くなるんじゃ!!って思いますよね?

ということで、弊社システムをPHP7に移行してみた時の事を書きたいと思います。※もちろん実施したのは開発環境です。

PHP7に移行!!

出来ませんでしたorz

なぜ移行出来なかったのか。少し説明します。

弊社システムは CakePHP2.x系 を利用してます。
そして、CakePHPのコアユーティリティの中に「String」クラスが有ります。

PHP: rfc:reserve_more_types_in_php_7

このRFCにより、型名と同じクラスを作成出来ないようになっています。
エラーメッセージはこんな感じ

Fatal error: Cannot use 'String' as class name as it is reserved in /path/to/cakephp/lib/Cake/Utility/String.php on line 25

ということで撃沈。。

ですが、どうしても動かしたかったのでとりあえず String クラスのクラス名を変更してみました。
すると・・・・

またダメでした!

次のエラーはこんな感じ

Fatal error: Uncaught TypeError: Argument  1 passed to ErrorHandler::handleException() must be an instance of Exception, instance of Error given in ...

エラーハンドリングの関数で、引数の型宣言に Exception を指定してるけど、実際は Error が渡されているようです。
※どっかで致命的エラーが出てる?

だがしかし!諦めずに修正していきます。

ErrorHandler::handleException() の型宣言を「Throwable」にしました。
Error や Exception は Throwable インターフェースを継承しています。なので型宣言を Throwable にしておくと、とりあえずOKなハズです。

すると・・・・

f:id:sekaie:20151112141749p:plain

出ました!!!

やったー!ヽ(=´▽`=)ノ

と思ったのもつかの間、次は cookie が取得できないという現象が発生しました。
Cookie コンポーネントか Session コンポーネント辺りが怪しい

今回はここで諦めたので結局移行することは出来ませんでした。
しかしPHP7への移行はわりとハードル低いんじゃないかな?と感じました。後方互換を考えて実装してくれているようですし。
利用しているフレームワークの対応状況もかなり影響すると思いますが。。

おわりに

リリース予定だった11月12日にはまだ本リリースされず、RC7がリリースされました。
新しいタイムテーブルによると11月26日がリリース日となっています。

https://wiki.php.net/todo/php70#timetable

待ち遠しい限りですね。

ほな!