PHP7.4がリリースされた
今回のアップデートも目まぐるしい機能が多く追加されました
機能の紹介は既にあるたくさんの記事にお任せするとして、個人的に気になっていた新機能 FFIを試してみます
FFIとは
Foreign Function Interface
の略でPHPで別の言語を動かせる機能です
Cなどで実装した共有ライブラリを読み込んで、利用することができます
メリットとしては実行速度が速くなることが大きいかと思われます
FFIでGoを利用する
本題です
Goを利用するにはGoで共有ライブラリを実装する必要があります
何故Goを利用するのか
Cより簡単だから
Goで共有ライブラリを作るには
- packageをmainにする
- main関数が必要
- exportする関数に
//export [function name]
のコメントを書く - ビルド時は
-buildmode=c-shared
を付ける
今回はフィボナッチ数を計算するプログラムを用意しました
再帰を使っていて数が大きくなるほど計算に時間がかかるサンプルです
package main
import "C"
//export calcFibonacci
func calcFibonacci(i uint) uint {
if i < 2 {
return i
}
return calcFibonacci(i - 1) + calcFibonacci(i - 2)
}
func main() {}
ビルド
説明通り -buildmode=c-shared
を付けてビルドします
出力ファイル名は、Windowsの場合は *.dll
、macOSでは *.dylib
、Linuxでは *.so
でしょうか
今回はmacOSを使っているので、 fibonacci.dylib
というファイル名を指定しました
ビルドを済ませると指定したファイル名のバイナリと同じ名前の *.h
ファイルが生成されているはずです
このヘッダーファイルを用いることで他のプログラムから利用することができます
(今回はこのヘッダーファイルを利用しない方法で説明します)
PHPからFFIでGoを利用する
準備が整ったのでいよいよFFIを利用します
cdef関数を利用します
一つ目の引数にC形式での関数定義
二つ目の引数に共有ライブラリへのパスを指定します
$ffi = FFI::cdef(
'extern unsigned int calcFibonacci(unsigned int p0);',
'[PATH]/fibonacci.dylib'
);
あとはこのように呼び出すことができます
echo($ffi->calcFibonacci(10)); // 55
以上がFFIからGoを利用する方法です
では、続いてどれだけ実行速度に差が出るか比較してみます
FFIでPHPはどれだけ速くなるか
以下のような検証用プログラムを作成しました
FFIとPHPそれぞれでフィボナッチ数列を40番目まで求めるプログラムです
実行はCLIから行いました
const COUNT = 40;
$ffi = FFI::cdef(
'extern unsigned int calcFibonacci(unsigned int p0);',
'[PATH]/fibonacci.dylib'
);
// 比較対象のPHP実装サンプル
function calcFibonacci(int $i): int {
if ($i < 2) {
return $i;
}
return calcFibonacci($i - 1) + calcFibonacci($i - 2);
}
// Go(FFI)実装の実行速度計測
$startTime = microtime(true);
for($i = 1; $i <= COUNT; $i++) {
$ffi->calcFibonacci($i);
}
$time = microtime(true) - $startTime;
echo "Go(FFI): {$time} 秒\n";
// PHP実装の実行速度計測
$startTime = microtime(true);
for($i = 1; $i <= COUNT; $i++) {
calcFibonacci($i);
}
$time = microtime(true) - $startTime;
echo "PHP: {$time} 秒\n";
結果
Go(FFI): 1.5760109424591 秒
PHP: 33.616943836212 秒
かなり大きな差が出ていると思います
PHPで重い処理を行う場合に、FFIはかなり強みになると感じました