Hack/HHVM 入門
2014/05/02 社内勉強会資料 1
はじめに
Hack とは?
◦ プログラミング言語である
◦ Facebook が作った
HHVM とは?
◦ Hack プログラムを実行する VM である
$ /usr/bin/hhvm hello.hh
Hello, world!
2014/05/02 社内勉強会資料 2
Hack はどんな言語?
PHP の言語拡張
◦ 型アノテーション
◦ ジェネリクス
◦ Null許容型
◦ コンテナ型
◦ etc.
したがって PHP のプログラムは Hack のプログラムでもある
$ /usr/bin/hhvm hello.php
Hello, world!
2014/05/02 社内勉強会資料 3
今日の話
HHVM を使う
◦ Yet another PHP interpreter として
プログラミング言語 Hack
2014/05/02 社内勉強会資料 4
HHVM を使う
2014/05/02 社内勉強会資料 5
メリットは?
2014/05/02 社内勉強会資料 6
速い
ベンチマーク
2014/05/02 社内勉強会資料 7
17.93
14.00
20.19
15.81
15.10
12.54
13.77
10.64
2.16
14.13
1.92
2.21
9.37
7.72
2.81
5.45
#N/A
10.53
5.70
2.48
0
5
10
15
20
25
PHP と HHVM の実行時間の比較 [秒]
PHP HHVM
The Computer Language Benchmarks Game
http://benchmarksgame.alioth.debian.org/
各問題の PHP 最速コードを利用
インストール手順
Ubuntu Server 13.10
◦ Hack のウェブサイトの情報どおり
◦ 現時点では素直に Ubuntu を使うのがオススメ
◦ Debian でも大丈夫だろうと思うが試していない
CentOS 6.5
◦ 試したが上手くいかなかった
◦ CentOS のパッケージが古すぎる
◦ 公式から入れようとしたら binutils のバージョン違いを解決できなかった
◦ hop5 という野良リポジトリから一応は入ったが Apache と連携できず
Windows / Macintosh / その他
◦ 試していない
2014/05/02 社内勉強会資料 8
Ubuntu Server 13.10
ウェブサイトの手順どおり
◦ http://hhvm.com/blog/3203/nightly-packages
2014/05/02 社内勉強会資料 9
$ wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo
apt-key add -
$ echo deb http://dl.hhvm.com/ubuntu saucy main | sudo tee
/etc/apt/sources.list.d/hhvm.list
$ sudo apt-get update
$ sudo apt-get install hhvm-nightly
動かす
Hello, world!
2014/05/02 社内勉強会資料 10
$ vi hello.hh
<?hh
print "Hello, world!¥n";
$ hhvm hello.hh
Hello, world!
$ vi hello.php
<?php
print "Hello, world!¥n";
$ hhvm hello.php
Hello, world!
Apache との連携
FastCGI (mod_fcgi) を使う
◦ 電子書籍が参考になった
◦ 米林正明, Facebook発 新プログラミング言語「Hack」スタートアップガイド
◦ https://gihyo.jp/dp/ebook/2014/978-4-7741-6445-8
◦ 400 円
2014/05/02 社内勉強会資料 11
$ sudo apt-get install libapache2-mod-fcgid
$ cd /etc/apache2/mods-enabled
$ sudo ln -s ../mods-available/proxy.load
$ sudo ln -s ../mods-available/proxy_fcgi.load
$ sudo ln -s ../mods-available/hhvm_proxy_fcgi.conf
$ sudo service hhvm start
$ sudo service apache2 restart
確認する
phpinfo()
◦ HHVM では単に HipHop と表示されるだけ
2014/05/02 社内勉強会資料 12
$ sudo vi /var/www/phpinfo.php
<?php
phpinfo();
$ curl http://localhost/phpinfo.php
HipHop
詳細: HHVM サーバ
こんなプロセスが動いている
2014/05/02 社内勉強会資料 13
$ ps –ef | grep hhvm | 見やすいように切り貼り
/usr/bin/hhvm
--config /etc/hhvm/server.ini
--user www-data
--mode daemon -vPidFile=/var/run/hhvm/pid
詳細: サーバ設定
2014/05/02 社内勉強会資料 14
$ cat /etc/hhvm/server.ini
; php options
pid = /var/run/hhvm/pid
; hhvm specific
hhvm.server.port = 9000
hhvm.server.type = fastcgi
hhvm.server.default_document = index.php
hhvm.log.level = Warning
hhvm.log.always_log_unhandled_exceptions = true
hhvm.log.runtime_error_reporting_level = 8191
hhvm.log.use_log_file = true
hhvm.log.file = /var/log/hhvm/error.log
hhvm.repo.central.path = /var/run/hhvm/hhvm.hhbc
hhvm.mysql.typed_results = false
詳細: Apache の Proxy 設定
2014/05/02 社内勉強会資料 15
$ cat /etc/apache2/mods-enabled/hhvm_proxy_fcgi.conf
ProxyPassMatch
^/(.*¥.(hh|php)(/.*)?)$ fcgi://127.0.0.1:9000/var/www/$1
Symfony を乗せてみる
ウェブサイトの説明どおりにインストール
◦ http://symfony.com/doc/current/quick_tour/the_big_picture.html
2014/05/02 社内勉強会資料 16
$ curl -sS https://getcomposer.org/installer | php
$ ./composer.phar create-project symfony/framework-
standard-edition /var/www/symfony/ ~2.4
いつもの設定
$ chmod 777 /var/www/symfony/app/{cache,logs}
$ sudo vi /etc/hhvm/server.ini
; php options
pid = /var/run/hhvm/pid
date.timezone = Asia/Tokyo
確認する
http://localhost/symfony/web/app_dev.php/demo/hello/World
2014/05/02 社内勉強会資料 17
PHP との互換性
ウェブサイトの PHP 関数リファレンスを参照
◦ http://docs.hhvm.com/manual/en/phpfuncref.php
◦ 関数ごとに HHVM の対応状況が記載されている
2014/05/02 社内勉強会資料 18
高速化のための約束
トップレベルに処理を書かないこと
◦ おそらく JIT の対象外
2014/05/02 社内勉強会資料 19
$ cat test1.hh
<?hh
for($i=0;$i<10000000;++$i);
$ time hhvm test1.hh
real 0m1.410s
user 0m1.371s
sys 0m0.036s
$ cat test2.hh
<?hh
function test() {
for($i=0;$i<10000000;++$i);
}
test();
$ time hhvm test2.hh
real 0m0.186s
user 0m0.147s
sys 0m0.036s
実は最初のベンチマーク結果には嘘があります
ベンチマーク (真実)
2014/05/02 社内勉強会資料 20
17.93
14.00
20.19
15.81
15.10
12.54
13.77
10.64
2.16
14.13
1.84
26.67
9.40
7.44
60.45
24.17
#N/A
10.67
7.86
2.45
1.92
2.21
9.37
7.72
2.81
5.45
#N/A
10.53
5.70
2.48
0
10
20
30
40
50
60
70
PHP と HHVM の実行時間の比較 [秒]
PHP PHP on HHVM HHVM
プログラミング言語 Hack
2014/05/02 社内勉強会資料 21
メリットは?
2014/05/02 社内勉強会資料 22
静的な型検査
すぐ炎上するので小さな声で言います
Hack の言語機能
ウェブサイトのリファレンス
◦ http://docs.hhvm.com/manual/en/hacklangref.php
◦ これを読めばだいたいわかる
2014/05/02 社内勉強会資料 23
独習 Hack
ウェブサイトのチュートリアル
◦ http://hacklang.org/tutorial
◦ これをやればだいたいわかる
2014/05/02 社内勉強会資料 24
◦ エディタになっていて自由にコードを書ける
独断と偏見による分類
静的型に関する機能
◦ Type Annotation
◦ Generics
◦ Nullable
◦ Type Aliasing
さまざまな複合データ型
◦ Collections
◦ Vector, Map, Set, Pair
◦ Shapes
◦ Tuples
その他 (わりとどーでもいい)
◦ Hack Modes
◦ Async
◦ Continuations
◦ Traits / Trait Requirements
◦ Lambda Expressions
2014/05/02 社内勉強会資料 25
以下のスライドでは下線を引いた機能をピックアップして紹介
Type Annotation
型を書くのは・・・
◦ 関数定義の引数と戻り値
◦ クラスのメンバ変数
関数内部のローカル変数には型を書かない
◦ 型を書かない != 型が付かない
◦ 書かなくても自動的に推論して型エラーを検出する
2014/05/02 社内勉強会資料 26
$ vi test.hh
<?hh
function add(int $a, int $b): int {
$c = $a + $b;
return $c;
}
型検査の実行
hh_client を使う
2014/05/02 社内勉強会資料 27
$ touch .hhconfig
$ hh_client check
No errors!
$ hh_client stop
◦ 裏側で hh_server プロセスが起動し .hhconfig 以下を監視するらしい
◦ hh_client stop で hh_server プロセスを停止する
型エラーの検出
◦ 関数の戻り値の型は int でなければいけない
◦ ところが、引数の $b が float なので $c は int + float = float である
◦ というわけで、戻り値の型が正しくないと文句を言っている
2014/05/02 社内勉強会資料 28
$ vi test.hh
<?hh
function add_error(int $a, float $b): int {
$c = $a + $b;
return $c;
}
$ hh_client check
/.../test.hh:4:10,11: Invalid return type
/.../test.hh:2:39,41: This is an int
/.../test.hh:2:28,32: It is incompatible with a float
型エラーの修正
◦ intval 関数を入れることで $c の型が int になった
◦ 単に int にキャストする方法でも同じ
2014/05/02 社内勉強会資料 29
$ vi test.hh
<?hh
function add_error_fixed(int $a, float $b): int {
$c = intval($a + $b);
return $c;
}
$ hh_client check
No errors!
Nullable
◦ 型の先頭に ? を書くと null 許容型になる
このプログラムには型エラーがあります (次のスライドで説明)
2014/05/02 社内勉強会資料 30
$ vi test.hh
<?hh
function add_null(?int $a, int $b): int {
$c = $a + $b;
return $c;
}
Nullable (型エラーの検出)
◦ $a は算術演算子 “+” で使われるので int か float でなければいけない
◦ ところが $a は null 許容型である
◦ というわけで、型のエラーだと文句を言っている
2014/05/02 社内勉強会資料 31
<?hh
function add_null(?int $a, int $b): int {
$c = $a + $b;
return $c;
}
$ hh_client check
/.../test.hh:3:8,9: Typing error
/.../test.hh:3:8,9: This is a num (int/float) because
this is used in an arithmetic operation
/.../test.hh:2:19,22: It is incompatible with a nullable
type
Nullable (型エラーの修正)
◦ null のときは 0 を代入することで、演算の箇所での $a は int になった
◦ 三項演算子を使って書いても同じ
2014/05/02 社内勉強会資料 32
$ vi test.hh
<?hh
function add_null(?int $a, int $b): int {
if ($a == null) {
$a = 0;
}
$c = $a + $b;
return $c;
}
$ hh_client check
No errors!
Shape
2014/05/02 社内勉強会資料 33
$ vi test.hh
<?hh
type person = shape('name' => string, 'age' => int);
function is_adult(person $p) : bool {
return $p['age'] >= 20;
}
function test() {
$taro = shape('name' => 'Taro', 'age' => 25);
echo is_adult($taro) . "¥n";
}
◦ Key の値が固定された配列
◦ 右辺の型に person という名前を付けている (type aliasing; 後述)
Shape (型エラーの検出)
◦ $no_name には “name” フィールドが無い
◦ is_adult 関数の引数 $p は person 型で “name” フィールドが定義済み
◦ というわけで、引数の型が正しくないと文句を言っている
2014/05/02 社内勉強会資料 34
function is_adult(person $p) : bool { ... }
function test() {
$no_name = shape('age' => 25); // name が無い
echo is_adult($no_name) . "¥n";
}
$ hh_client check
/.../test.hh:10:17,24: Invalid argument
/.../test.hh:9:14,18: The field 'name' is missing
/.../test.hh:4:19,24: The field 'name' is defined
Shape (初期化後の代入)
◦ 左は OK, 右は NG
◦ Shape のキーには定数文字列しか使えない
2014/05/02 社内勉強会資料 35
function test() {
$taro = shape();
$taro['name'] = 'Taro';
$taro['age'] = 25;
echo is_adult($taro)."¥n";
}
function test() {
$taro = shape();
$taro['na'.'me'] = 'Taro';
$taro['age'] = 25;
echo is_adult($taro)."¥n";
}
$ hh_client check
/.../test.hh:10:9,19: Was expecting a constant string (for
shape access)
Type Aliasing
◦ 右辺のデータ型に左辺の別名を付ける
◦ プログラムが分かりやすくなる
2014/05/02 社内勉強会資料 36
$ vi test.hh
<?hh
type point = shape('x' => int, 'y' => int);
function new_point(int $x, int $y) : point {
return shape('x' => $x, 'y' => $y);
}
function get_x(point $p) : int { return $p['x']; }
function get_y(point $p) : int { return $p['y']; }
Type Aliasing (newtype)
◦ newtype を使うと、ファイルの外側からは右辺が見えなくなる
◦ プログラムのモジュール化に役立つ
2014/05/02 社内勉強会資料 37
$ vi test.hh
<?hh
newtype point = shape('x' => int, 'y' => int);
function new_point(int $x, int $y) : point {
return shape('x' => $x, 'y' => $y);
}
function get_x(point $p) : int { return $p['x']; }
function get_y(point $p) : int { return $p['y']; }
Type Aliasing (型エラーの検出)
◦ point の実体が shape(‘x’ => int, …) だということは隠されている
◦ というわけで、$p はコンテナではなく point だと文句を言っている
2014/05/02 社内勉強会資料 38
<?hh
require 'test.hh';
function main() : void {
$p = new_point(1, 2);
$p['x'] = 3;
}
$ hh_client check
/.../main.hh:6:3,9: This is not a container, this is an
object of type point
/.../main.hh:5:38,42: You might want to check this out
補足
2014/05/02 社内勉強会資料 39
hh_client と HHVM
HHVM では実行開始時に型検査するわけではない
◦ 関数の先頭で仮引数と実引数の型が合致しているか検査
◦ 関数を抜けるときに戻り値の型が合致しているか検査
hh_client がエラーにするコードも HHVM では実行できる
2014/05/02 社内勉強会資料 40
$ cat type_error.hh
<?hh
function test($cond): int { return $cond ? 1 : 'foo'; }
print test($argv[1]) . "¥n";
$ hhvm type_error.hh 1
1
$ hhvm type_error.hh 0
Fatal error: Value returned from test() must be of type
int, string given in /.../type_error.hh on line 3
おわり
2014/05/02 社内勉強会資料 41

Hack/HHVM 入門

  • 1.
  • 2.
    はじめに Hack とは? ◦ プログラミング言語である ◦Facebook が作った HHVM とは? ◦ Hack プログラムを実行する VM である $ /usr/bin/hhvm hello.hh Hello, world! 2014/05/02 社内勉強会資料 2
  • 3.
    Hack はどんな言語? PHP の言語拡張 ◦型アノテーション ◦ ジェネリクス ◦ Null許容型 ◦ コンテナ型 ◦ etc. したがって PHP のプログラムは Hack のプログラムでもある $ /usr/bin/hhvm hello.php Hello, world! 2014/05/02 社内勉強会資料 3
  • 4.
    今日の話 HHVM を使う ◦ Yetanother PHP interpreter として プログラミング言語 Hack 2014/05/02 社内勉強会資料 4
  • 5.
  • 6.
  • 7.
    ベンチマーク 2014/05/02 社内勉強会資料 7 17.93 14.00 20.19 15.81 15.10 12.54 13.77 10.64 2.16 14.13 1.92 2.21 9.37 7.72 2.81 5.45 #N/A 10.53 5.70 2.48 0 5 10 15 20 25 PHPと HHVM の実行時間の比較 [秒] PHP HHVM The Computer Language Benchmarks Game http://benchmarksgame.alioth.debian.org/ 各問題の PHP 最速コードを利用
  • 8.
    インストール手順 Ubuntu Server 13.10 ◦Hack のウェブサイトの情報どおり ◦ 現時点では素直に Ubuntu を使うのがオススメ ◦ Debian でも大丈夫だろうと思うが試していない CentOS 6.5 ◦ 試したが上手くいかなかった ◦ CentOS のパッケージが古すぎる ◦ 公式から入れようとしたら binutils のバージョン違いを解決できなかった ◦ hop5 という野良リポジトリから一応は入ったが Apache と連携できず Windows / Macintosh / その他 ◦ 試していない 2014/05/02 社内勉強会資料 8
  • 9.
    Ubuntu Server 13.10 ウェブサイトの手順どおり ◦http://hhvm.com/blog/3203/nightly-packages 2014/05/02 社内勉強会資料 9 $ wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo apt-key add - $ echo deb http://dl.hhvm.com/ubuntu saucy main | sudo tee /etc/apt/sources.list.d/hhvm.list $ sudo apt-get update $ sudo apt-get install hhvm-nightly
  • 10.
    動かす Hello, world! 2014/05/02 社内勉強会資料10 $ vi hello.hh <?hh print "Hello, world!¥n"; $ hhvm hello.hh Hello, world! $ vi hello.php <?php print "Hello, world!¥n"; $ hhvm hello.php Hello, world!
  • 11.
    Apache との連携 FastCGI (mod_fcgi)を使う ◦ 電子書籍が参考になった ◦ 米林正明, Facebook発 新プログラミング言語「Hack」スタートアップガイド ◦ https://gihyo.jp/dp/ebook/2014/978-4-7741-6445-8 ◦ 400 円 2014/05/02 社内勉強会資料 11 $ sudo apt-get install libapache2-mod-fcgid $ cd /etc/apache2/mods-enabled $ sudo ln -s ../mods-available/proxy.load $ sudo ln -s ../mods-available/proxy_fcgi.load $ sudo ln -s ../mods-available/hhvm_proxy_fcgi.conf $ sudo service hhvm start $ sudo service apache2 restart
  • 12.
    確認する phpinfo() ◦ HHVM では単にHipHop と表示されるだけ 2014/05/02 社内勉強会資料 12 $ sudo vi /var/www/phpinfo.php <?php phpinfo(); $ curl http://localhost/phpinfo.php HipHop
  • 13.
    詳細: HHVM サーバ こんなプロセスが動いている 2014/05/02社内勉強会資料 13 $ ps –ef | grep hhvm | 見やすいように切り貼り /usr/bin/hhvm --config /etc/hhvm/server.ini --user www-data --mode daemon -vPidFile=/var/run/hhvm/pid
  • 14.
    詳細: サーバ設定 2014/05/02 社内勉強会資料14 $ cat /etc/hhvm/server.ini ; php options pid = /var/run/hhvm/pid ; hhvm specific hhvm.server.port = 9000 hhvm.server.type = fastcgi hhvm.server.default_document = index.php hhvm.log.level = Warning hhvm.log.always_log_unhandled_exceptions = true hhvm.log.runtime_error_reporting_level = 8191 hhvm.log.use_log_file = true hhvm.log.file = /var/log/hhvm/error.log hhvm.repo.central.path = /var/run/hhvm/hhvm.hhbc hhvm.mysql.typed_results = false
  • 15.
    詳細: Apache のProxy 設定 2014/05/02 社内勉強会資料 15 $ cat /etc/apache2/mods-enabled/hhvm_proxy_fcgi.conf ProxyPassMatch ^/(.*¥.(hh|php)(/.*)?)$ fcgi://127.0.0.1:9000/var/www/$1
  • 16.
    Symfony を乗せてみる ウェブサイトの説明どおりにインストール ◦ http://symfony.com/doc/current/quick_tour/the_big_picture.html 2014/05/02社内勉強会資料 16 $ curl -sS https://getcomposer.org/installer | php $ ./composer.phar create-project symfony/framework- standard-edition /var/www/symfony/ ~2.4 いつもの設定 $ chmod 777 /var/www/symfony/app/{cache,logs} $ sudo vi /etc/hhvm/server.ini ; php options pid = /var/run/hhvm/pid date.timezone = Asia/Tokyo
  • 17.
  • 18.
    PHP との互換性 ウェブサイトの PHP関数リファレンスを参照 ◦ http://docs.hhvm.com/manual/en/phpfuncref.php ◦ 関数ごとに HHVM の対応状況が記載されている 2014/05/02 社内勉強会資料 18
  • 19.
    高速化のための約束 トップレベルに処理を書かないこと ◦ おそらく JITの対象外 2014/05/02 社内勉強会資料 19 $ cat test1.hh <?hh for($i=0;$i<10000000;++$i); $ time hhvm test1.hh real 0m1.410s user 0m1.371s sys 0m0.036s $ cat test2.hh <?hh function test() { for($i=0;$i<10000000;++$i); } test(); $ time hhvm test2.hh real 0m0.186s user 0m0.147s sys 0m0.036s 実は最初のベンチマーク結果には嘘があります
  • 20.
    ベンチマーク (真実) 2014/05/02 社内勉強会資料20 17.93 14.00 20.19 15.81 15.10 12.54 13.77 10.64 2.16 14.13 1.84 26.67 9.40 7.44 60.45 24.17 #N/A 10.67 7.86 2.45 1.92 2.21 9.37 7.72 2.81 5.45 #N/A 10.53 5.70 2.48 0 10 20 30 40 50 60 70 PHP と HHVM の実行時間の比較 [秒] PHP PHP on HHVM HHVM
  • 21.
  • 22.
  • 23.
  • 24.
    独習 Hack ウェブサイトのチュートリアル ◦ http://hacklang.org/tutorial ◦これをやればだいたいわかる 2014/05/02 社内勉強会資料 24 ◦ エディタになっていて自由にコードを書ける
  • 25.
    独断と偏見による分類 静的型に関する機能 ◦ Type Annotation ◦Generics ◦ Nullable ◦ Type Aliasing さまざまな複合データ型 ◦ Collections ◦ Vector, Map, Set, Pair ◦ Shapes ◦ Tuples その他 (わりとどーでもいい) ◦ Hack Modes ◦ Async ◦ Continuations ◦ Traits / Trait Requirements ◦ Lambda Expressions 2014/05/02 社内勉強会資料 25 以下のスライドでは下線を引いた機能をピックアップして紹介
  • 26.
    Type Annotation 型を書くのは・・・ ◦ 関数定義の引数と戻り値 ◦クラスのメンバ変数 関数内部のローカル変数には型を書かない ◦ 型を書かない != 型が付かない ◦ 書かなくても自動的に推論して型エラーを検出する 2014/05/02 社内勉強会資料 26 $ vi test.hh <?hh function add(int $a, int $b): int { $c = $a + $b; return $c; }
  • 27.
    型検査の実行 hh_client を使う 2014/05/02 社内勉強会資料27 $ touch .hhconfig $ hh_client check No errors! $ hh_client stop ◦ 裏側で hh_server プロセスが起動し .hhconfig 以下を監視するらしい ◦ hh_client stop で hh_server プロセスを停止する
  • 28.
    型エラーの検出 ◦ 関数の戻り値の型は intでなければいけない ◦ ところが、引数の $b が float なので $c は int + float = float である ◦ というわけで、戻り値の型が正しくないと文句を言っている 2014/05/02 社内勉強会資料 28 $ vi test.hh <?hh function add_error(int $a, float $b): int { $c = $a + $b; return $c; } $ hh_client check /.../test.hh:4:10,11: Invalid return type /.../test.hh:2:39,41: This is an int /.../test.hh:2:28,32: It is incompatible with a float
  • 29.
    型エラーの修正 ◦ intval 関数を入れることで$c の型が int になった ◦ 単に int にキャストする方法でも同じ 2014/05/02 社内勉強会資料 29 $ vi test.hh <?hh function add_error_fixed(int $a, float $b): int { $c = intval($a + $b); return $c; } $ hh_client check No errors!
  • 30.
    Nullable ◦ 型の先頭に ?を書くと null 許容型になる このプログラムには型エラーがあります (次のスライドで説明) 2014/05/02 社内勉強会資料 30 $ vi test.hh <?hh function add_null(?int $a, int $b): int { $c = $a + $b; return $c; }
  • 31.
    Nullable (型エラーの検出) ◦ $aは算術演算子 “+” で使われるので int か float でなければいけない ◦ ところが $a は null 許容型である ◦ というわけで、型のエラーだと文句を言っている 2014/05/02 社内勉強会資料 31 <?hh function add_null(?int $a, int $b): int { $c = $a + $b; return $c; } $ hh_client check /.../test.hh:3:8,9: Typing error /.../test.hh:3:8,9: This is a num (int/float) because this is used in an arithmetic operation /.../test.hh:2:19,22: It is incompatible with a nullable type
  • 32.
    Nullable (型エラーの修正) ◦ nullのときは 0 を代入することで、演算の箇所での $a は int になった ◦ 三項演算子を使って書いても同じ 2014/05/02 社内勉強会資料 32 $ vi test.hh <?hh function add_null(?int $a, int $b): int { if ($a == null) { $a = 0; } $c = $a + $b; return $c; } $ hh_client check No errors!
  • 33.
    Shape 2014/05/02 社内勉強会資料 33 $vi test.hh <?hh type person = shape('name' => string, 'age' => int); function is_adult(person $p) : bool { return $p['age'] >= 20; } function test() { $taro = shape('name' => 'Taro', 'age' => 25); echo is_adult($taro) . "¥n"; } ◦ Key の値が固定された配列 ◦ 右辺の型に person という名前を付けている (type aliasing; 後述)
  • 34.
    Shape (型エラーの検出) ◦ $no_nameには “name” フィールドが無い ◦ is_adult 関数の引数 $p は person 型で “name” フィールドが定義済み ◦ というわけで、引数の型が正しくないと文句を言っている 2014/05/02 社内勉強会資料 34 function is_adult(person $p) : bool { ... } function test() { $no_name = shape('age' => 25); // name が無い echo is_adult($no_name) . "¥n"; } $ hh_client check /.../test.hh:10:17,24: Invalid argument /.../test.hh:9:14,18: The field 'name' is missing /.../test.hh:4:19,24: The field 'name' is defined
  • 35.
    Shape (初期化後の代入) ◦ 左はOK, 右は NG ◦ Shape のキーには定数文字列しか使えない 2014/05/02 社内勉強会資料 35 function test() { $taro = shape(); $taro['name'] = 'Taro'; $taro['age'] = 25; echo is_adult($taro)."¥n"; } function test() { $taro = shape(); $taro['na'.'me'] = 'Taro'; $taro['age'] = 25; echo is_adult($taro)."¥n"; } $ hh_client check /.../test.hh:10:9,19: Was expecting a constant string (for shape access)
  • 36.
    Type Aliasing ◦ 右辺のデータ型に左辺の別名を付ける ◦プログラムが分かりやすくなる 2014/05/02 社内勉強会資料 36 $ vi test.hh <?hh type point = shape('x' => int, 'y' => int); function new_point(int $x, int $y) : point { return shape('x' => $x, 'y' => $y); } function get_x(point $p) : int { return $p['x']; } function get_y(point $p) : int { return $p['y']; }
  • 37.
    Type Aliasing (newtype) ◦newtype を使うと、ファイルの外側からは右辺が見えなくなる ◦ プログラムのモジュール化に役立つ 2014/05/02 社内勉強会資料 37 $ vi test.hh <?hh newtype point = shape('x' => int, 'y' => int); function new_point(int $x, int $y) : point { return shape('x' => $x, 'y' => $y); } function get_x(point $p) : int { return $p['x']; } function get_y(point $p) : int { return $p['y']; }
  • 38.
    Type Aliasing (型エラーの検出) ◦point の実体が shape(‘x’ => int, …) だということは隠されている ◦ というわけで、$p はコンテナではなく point だと文句を言っている 2014/05/02 社内勉強会資料 38 <?hh require 'test.hh'; function main() : void { $p = new_point(1, 2); $p['x'] = 3; } $ hh_client check /.../main.hh:6:3,9: This is not a container, this is an object of type point /.../main.hh:5:38,42: You might want to check this out
  • 39.
  • 40.
    hh_client と HHVM HHVMでは実行開始時に型検査するわけではない ◦ 関数の先頭で仮引数と実引数の型が合致しているか検査 ◦ 関数を抜けるときに戻り値の型が合致しているか検査 hh_client がエラーにするコードも HHVM では実行できる 2014/05/02 社内勉強会資料 40 $ cat type_error.hh <?hh function test($cond): int { return $cond ? 1 : 'foo'; } print test($argv[1]) . "¥n"; $ hhvm type_error.hh 1 1 $ hhvm type_error.hh 0 Fatal error: Value returned from test() must be of type int, string given in /.../type_error.hh on line 3
  • 41.