Post on 05-Dec-2014
description
Hack/HHVM 入門
2014/05/02 社内勉強会資料 1
はじめにHack とは?◦ プログラミング言語である
◦ Facebook が作った
HHVM とは?◦ Hack プログラムを実行する VM である
$ /usr/bin/hhvm hello.hhHello, world!
2014/05/02 社内勉強会資料 2
Hack はどんな言語?PHPの言語拡張◦ 型アノテーション
◦ ジェネリクス
◦ Null許容型
◦ コンテナ型
◦ etc.
したがって PHP のプログラムは Hack のプログラムでもある
$ /usr/bin/hhvm hello.phpHello, 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.9
3
14.0
0
20.1
9
15.8
1
15.1
0
12.5
4
13.7
7
10.6
4
2.1
6
14.1
3
1.9
2
2.2
1
9.3
7
7.7
2
2.8
1
5.4
5
#N
/A
10.5
3
5.7
0
2.4
8
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 | sudoapt-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<?hhprint "Hello, world!¥n";$ hhvm hello.hhHello, world!
$ vi hello.php<?phpprint "Hello, world!¥n";$ hhvm hello.phpHello, 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<?phpphpinfo();$ curl http://localhost/phpinfo.phpHipHop
詳細: 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 = 9000hhvm.server.type = fastcgihhvm.server.default_document = index.phphhvm.log.level = Warninghhvm.log.always_log_unhandled_exceptions = truehhvm.log.runtime_error_reporting_level = 8191hhvm.log.use_log_file = truehhvm.log.file = /var/log/hhvm/error.loghhvm.repo.central.path = /var/run/hhvm/hhvm.hhbchhvm.mysql.typed_results = false
詳細: Apache の Proxy 設定
2014/05/02 社内勉強会資料 15
$ cat /etc/apache2/mods-enabled/hhvm_proxy_fcgi.confProxyPassMatch^/(.*¥.(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/piddate.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.410suser 0m1.371ssys 0m0.036s
$ cat test2.hh<?hhfunction test() {for($i=0;$i<10000000;++$i);}test();$ time hhvm test2.hh
real 0m0.186suser 0m0.147ssys 0m0.036s
実は最初のベンチマーク結果には嘘があります
ベンチマーク (真実)
2014/05/02 社内勉強会資料 20
17.9
3
14.0
0
20.1
9
15.8
1
15.1
0
12.5
4
13.7
7
10.6
4
2.1
6
14.1
3
1.8
4 2
6.6
7
9.4
0
7.4
4
60.4
5
24.1
7
#N
/A
10.6
7
7.8
6
2.4
5
1.9
2
2.2
1
9.3
7
7.7
2
2.8
1
5.4
5
#N
/A
10.5
3
5.7
0
2.4
8
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<?hhfunction add(int $a, int $b): int {$c = $a + $b;return $c;
}
型検査の実行hh_clientを使う
2014/05/02 社内勉強会資料 27
$ touch .hhconfig$ hh_client checkNo 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<?hhfunction 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<?hhfunction add_error_fixed(int $a, float $b): int {$c = intval($a + $b);return $c;
}
$ hh_client checkNo errors!
Nullable
◦ 型の先頭に ? を書くと null 許容型になる
このプログラムには型エラーがあります (次のスライドで説明)
2014/05/02 社内勉強会資料 30
$ vi test.hh<?hhfunction add_null(?int $a, int $b): int {$c = $a + $b;return $c;
}
Nullable (型エラーの検出)
◦ $a は算術演算子 “+” で使われるので intか float でなければいけない
◦ ところが $a は null 許容型である
◦ というわけで、型のエラーだと文句を言っている
2014/05/02 社内勉強会資料 31
<?hhfunction 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<?hhfunction add_null(?int $a, int $b): int {if ($a == null) {$a = 0;
}$c = $a + $b;return $c;
}
$ hh_client checkNo errors!
Shape
2014/05/02 社内勉強会資料 33
$ vi test.hh<?hhtype 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<?hhtype 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<?hhnewtype 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
<?hhrequire '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と HHVMHHVM では実行開始時に型検査するわけではない◦ 関数の先頭で仮引数と実引数の型が合致しているか検査
◦ 関数を抜けるときに戻り値の型が合致しているか検査
hh_clientがエラーにするコードも HHVM では実行できる
2014/05/02 社内勉強会資料 40
$ cat type_error.hh<?hhfunction test($cond): int { return $cond ? 1 : 'foo'; }print test($argv[1]) . "¥n";$ hhvm type_error.hh 11$ hhvm type_error.hh 0Fatal error: Value returned from test() must be of type int, string given in /.../type_error.hh on line 3
おわり
2014/05/02 社内勉強会資料 41