SlideShare a Scribd company logo
PHPからC#のライブラリを
呼べるようにしたdotnet_ffiを
趣味でつくってみた
よーがす @pg_ito
(アバター: 佐波野いりこ @SabanoIriko)
PHP Conference Japan 2022 09/25
自己紹介
● エンジニア
最近は主にPHP、C#、たまにC++、JavaScript
サーバの負荷対策が好き
● 趣味
配信、電子工作、スプラトゥーン3
名前: よーがす
Twitter: @pg_ito
Blog: https://b64.pw/blog/
もくじ
● dotnet_ffiってなに?
● 作った動機
● 想定される利用ケース
● dotnet_ffiの構成
● dotnet_ffiの簡単な使い方
● CoreCLRって?
● Extensionを作るための情報源
● 今後の展望
dotnet_ffiってなに?
dotnet_ffiってなに?
PHPからC#のライブラリを直接呼べるようにしたPHP Extension
CoreCLRをつかってC#のDLLを動的にロード、実行している
PHPプロセスが作り直されるまでC#のVMを使いまわすので
C#のJITの恩恵を得られて高速に動作
リポジトリ: https://github.com/pg-ito/dotnet_ffi
(MITライセンス)
パフォーマンス比較
fibonacci数を計算させた場合PHPのみに比べて約16倍ほど高速(PHP8.1.6の場合)
作った動機
作った動機
・Unityと同じ処理をPHPサーバ側でも行いたい
・Extensionを書かずに手軽にPHPの処理を高速化したい
・C#にしかない機能を使いたい
想定される利用ケース
UnityClientと処理の共通化
・ゲームのチート対策
クライアントから送られてきたデータが不正なものでないか
正規のクライアント側のC#の処理と比較できる
・バリデータの共通化
APIのエラーチェックなどを一元化できる
処理の高速化
・CPU使用率の高い処理をC#側で高速に行える
例えばfibonacci数を求めるような処理で効果を発揮
(リポジトリ内のベンチマークにこのケースを想定したコードを同梱)
C#にしかないライブラリの利用
・Linqでのデータの抽出
多次元配列を任意の形に整形
(おそらくPHPのみで書かれている限りPHP移植版Linqにくらべて高速な…ハズ)
dotnet_ffiの構成
PHP Process
設計の特徴
・PHP ExtensionがC/C++で書けることを利用してCoreCLR経由でC#とバインド
PHP ➡ dotnet_ffi(C,C++) ➡ CoreCLR(C++) ➡ C# Library
PHP 標準
Extension
CoreCLR (C++)
C# Library
PHP
標準関数等
PHP
言語
構造
dotnet_ffi (C, C++)
※CoreCLRについては後述
PHP8対応での影響
・ARG_INFOの対応
PHP8でビルドするとついにwarningが出るようになった。
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &arg1, &arg2) == FAILURE) {
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ret_s64_arg_s64_s64,
0, 2, IS_LONG, 0)
ZEND_ARG_INFO(0, long_arg1)
ZEND_ARG_INFO(0, long_arg2)
ZEND_END_ARG_INFO()
PHP_ME(DotnetFFI, ret_s64_arg_s64_s64, arginfo_ret_s64_arg_s64_s64,
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
型情報を追加
dotnet_ffiの簡単な使い方
ビルド
・ソースのクローン
git clone https://github.com/pg-ito/dotnet_ffi.git .
・docker composeでビルドと実行
cd build_env
docker compose -up -d --build
docker compose exec php_fpm /bin/bash -c "cd /var/www && ./br.sh && ./run.sh"
・もし直接ビルドする場合
yum install -y devtoolset-7-gcc devtoolset-7-gcc-c++
yum install -y --enablerepo=epel,remi,remi-php81 php php-devel
yum install -y dotnet-sdk-6.0
./br.sh
dotnet_ffiの簡単な使い方
・引数がint、戻り値もintの場合の呼び出し方
$retInt64 = DotnetFFI::ret_s64_arg_s64(30);
※デフォルト設定だとdotnet_dllディレクトリにある
fibonacci数のサンプルコードを呼び出すようになっている(iniで変更可)
・実行
docker compose exec php_fpm /bin/bash -c "cd /var/www && ./run.sh mycode.php"
・その他サンプルコード
./ext_test.php … 各種メソッドの動作サンプル
./benchmarker/runbench.php … フィボナッチのベンチマーク
CoreCLRって?
CoreCLRって?
・.NETの実行環境
ほかのC/C++のプログラムに.NETのVM(※CLI)を
組み込むことができるライブラリ(というかこれ自体で.NETを動かしている)
dotnet_ffiはこれを使ってPHP ExtensionからC#を実行している
※CLI…Common Language Infrastructure
※CoreCLRリポジトリ
https://github.com/dotnet/coreclr/tree/v3.1.29
・CoreFX、Mono Runtime等と類似の役割
※参考: Embedding Mono
https://www.mono-project.com/docs/advanced/embedding/
CoreCLRの使い方(初期化)
・libcoreclr.soをdlopenする
coreClr = dlopen(coreClrPath.c_str(), RTLD_NOW | RTLD_LOCAL);
・dlsymでそれぞれのシンボルのアドレスを取得
initializeCoreClr = (coreclr_initialize_ptr)dlsym(coreClr, "coreclr_initialize");
createManagedDelegate = (coreclr_create_delegate_ptr)dlsym(coreClr,
"coreclr_create_delegate");
shutdownCoreClr = (coreclr_shutdown_ptr)dlsym(coreClr, "coreclr_shutdown");
CoreCLRの使い方(初期化)
・CoreCLR初期化
CoreCLRにpublishされたC#の.dllファイルパスを「:」区切りで
propertyValuesに一通りわたして初期化します
int hr = initializeCoreClr(
runtimePath, // App base path
"HostingOnPHP", // AppDomain friendly name
sizeof(propertyKeys) / sizeof(char*), // Property count
propertyKeys, // Property names
propertyValues, // Property values
&hostHandle, // Host handle
&domainId); // AppDomain ID
dotnet_ffiではPHPプロセスが作られるタイミングで初期化
PHP_MINIT_FUNCTION(dotnet_ffi)
CoreCLRの使い方(C#呼び出し)
・C#のメソッドの関数ポインタを取得
C#のプロジェクト名、名前空間までつけた完全修飾のクラス名、メソッド名とC#のクラスへ
のアドレスが格納されるポインタを渡す
*hr = createManagedDelegate (
hostHandle,
domainId,
target_project_name .c_str(),
target_class_name.c_str(),
method_name,
(void**)&managedDelegateInvokeReturnString);
・C#のメソッド呼び出し
std::string ret = managedDelegateInvokeReturnString(inStr);
この関数ポインタを実行することで
C#のメソッドを呼び出せる
CoreCLRの使い方(終了)
・C#のCoreCLRの終了
使い終わったらshutdown
dotnet_ffiではphpプロセスが作り直されるタイミングにあわせてシャットダウン
(VMの生成と初回JITコンパイルコストが高いので)
int hr = shutdownCoreClr(hostHandle, domainId);
dotnet_ffiではPHPのプロセスが終了するタイミング
PHP_MSHUTDOWN_FUNCTION(dotnet_ffi)
Extensionを作るための情報源
Extensionについての公式ドキュメント
公式のExtensionのドキュメントはない(2022年9月時点)
以前は「PHP のコア: ハッカーの手引き」という項目があったが無くなっている
それもPHP5.3.3頃で止まっている模様
検索しても非公式のミラーがいくつか引っ掛かる程度
(それもTLS対応していないサイトだったりする)
PHPのソースを追いましょう
現時点で一番確実なのはPHPのソースを追う
PHPのソースにあたることで下記の情報が得られる
・Extensionのひな形の作り方
・Extensionとしてのクラスや関数の宣言のしかた
・PHP用のconfig.m4の書き方
※ソースを追うときには使いたい PHPバージョンのタグを指定して追うのが安全
Extensionのひな形の作り方
そもそもどこからExtension開発に手を付けていいかがわかりづらいが
PHPのソース内のextディレクトリを探すと
ext_skel.phpというスクリプトがあり、これでひな形が作れる
https://github.com/php/php-src/blob/php-8.1.10/ext/ext_skel.php
php ext_skel.php --help
とするとExtensionのひな形の作り方やビルドのしかたがでてくる
Extensionのひな形の作り方
extension_exampleというExtensionを作る場合の例
php ext_skel.php --ext extension_example
cd extension_example
phpize
./configure
make
make test
※PECLでXMLを書いてひな形にする方法もあります
ここに作りたいExtension名を指定する
Extensionとしてのクラスや関数の宣言のしかた
旧公式ドキュメントでもExtensionの関数の宣言のやり方は載っていたが
Extensionとしてのクラスの宣言方法は載っていなかった
PHPの標準クラスで似たようなインターフェイスのクラスを探して
その書き方を参考にするのが楽
同じextディレクトリ内にあるので色々見てみると参考になる
(個人的にはSQLite3のクラスが一通りそろっていて参考になった)
PHP用config.m4の書き方
ライブラリのリンクのしかたなど、automakeから拡張されているものもある
例えばライブラリをstatic linkする際の書き方などは、ほかのExtensionを調べたほうが
確実(一番調べるのに苦労した)
例
PHP_ADD_LIBRARY_WITH_PATH("coreclr_ctlpp", $DOTNET_FFI_DIR/coreclrhost, EXTRA_LDFLAGS)
今後の展望
今後の展望
・.NET7への対応
.NET7自体が速度向上しているのもあり、
間接的なPHPの処理速度向上が期待できそう
・呼び出しメソッドを可変化
C#側のメソッド名をPHPから動的に指定して実行できるようにしたい
但し、パフォーマンスが若干犠牲になる可能性あるので慎重にゆきたい
(現在はiniで指定する形、一度見つけた関数ポインタは使いまわし)
・PHP8.2への対応
リリースされ次第対応予定
要望等お気軽にお寄せください
おまけ: エンジニア系Vtuberはじめました
Twitter
@SabanoIriko
Youtube 佐波野いりこチャンネル
https://www.youtube.com/channel/UCQoB5I4tj36wgcvzIQrjpVA
↑よろしければチャンネル登録
よろしくお願いします_(._.)_

More Related Content

PPT
20050623 1
PPTX
広がる .Net
PPTX
OSC Tokyo/Spring NETMF 170311
PPTX
2015 1025 OSC-Fall Tokyo NETMF
PDF
DEV-002_.NET Core/ASP.NET Core が実現するクロスプラットフォーム .NET の今と未来
PDF
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
PDF
Photon Server Deep Dive - PhotonWireの実装から見つめるPhotonServerの基礎と応用
PDF
.NET最先端技術によるハイパフォーマンスウェブアプリケーション
20050623 1
広がる .Net
OSC Tokyo/Spring NETMF 170311
2015 1025 OSC-Fall Tokyo NETMF
DEV-002_.NET Core/ASP.NET Core が実現するクロスプラットフォーム .NET の今と未来
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Photon Server Deep Dive - PhotonWireの実装から見つめるPhotonServerの基礎と応用
.NET最先端技術によるハイパフォーマンスウェブアプリケーション

Similar to PHPからC#のライブラリを呼べるようにしたdotnet_ffiを趣味でつくってみた (12)

PDF
[Japan Tech summit 2017] APP 001
PDF
20131209_buildinsidermeetup
PDF
~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション
PDF
.NET 5 勉強会 ~.NET Framework から .NET へ~
PDF
RubyからFFIを使ってみた
PDF
.NET Coreから概観する.NETのOSSへの取り組み
PPTX
OSC Tokyo/Fall NETMF 161105
PDF
.NET Core 1.0
PDF
.NET の今と今後に思うこと (Tokyo Ver.)
PDF
改めて C# でできることを振り返る
PDF
.NET Coreとツール類の今
PPTX
OSC Nagoya NETMF 160528
[Japan Tech summit 2017] APP 001
20131209_buildinsidermeetup
~ Cloud First から Cloud Optimized へ ~ .NET on Cloud が描くモダナイゼーション
.NET 5 勉強会 ~.NET Framework から .NET へ~
RubyからFFIを使ってみた
.NET Coreから概観する.NETのOSSへの取り組み
OSC Tokyo/Fall NETMF 161105
.NET Core 1.0
.NET の今と今後に思うこと (Tokyo Ver.)
改めて C# でできることを振り返る
.NET Coreとツール類の今
OSC Nagoya NETMF 160528
Ad

PHPからC#のライブラリを呼べるようにしたdotnet_ffiを趣味でつくってみた