🧟

FrankenPHPとは何か

2024/03/10に公開

FrankenPHP

「サーバーとは何かを理解して、コンテナ1つで実行しよう | PHPerKaigi2024」 というスライドで FrankenPHP の話が出ており、以前から気になっていたので軽く調べてみました。

https://speakerdeck.com/sadnessojisan/sahatohahe-kawoli-jie-site-kontena1tuteshi-xing-siyou-phperkaigi2024

FrankenPHPとは

FrankenPHPとは簡単にいうとPHPを実行可能なWebサーバーです。公式サイトには次のように説明されています。

The Modern PHP App Server, written in Go

しかしこの説明だと少し大雑把で、実際にはFrankenPHPには大きく3つの側面があると感じました。

  1. PHPを実行可能なWebサーバー
    FrankenPHPは Caddy というGoで実装されたWebサーバー上でPHPを動かすのためのモジュールとして実行できる
  2. PHPを実行可能なCLI
    FrankenPHPはCLI上からもPHPファイル指定して実行できる(この場合はWebサーバーでないのでCaddyは使わない)
  3. Goのパッケージ
    FrankenPHPをGoのパッケージとして使えば、例えばGoのginやechoで実装されたWebサーバー上でPHPファイルを実行できたりする(通常はやらないと思うけど)

なぜこのような事ができるかというと、FrankenPHPにはPHPのソースが埋め込まれていて、それによりPHPがインストールされていなくてもFrankenPHPだけでPHPファイルを実行できるからです。そしてFrankenPHPはGoで実装されていることもあって、ビルドすれば1つの実行ファイルが出来上がり、その実行ファイルとPHPファイルさえあればPHPをできるという訳です。また一般的なPHP拡張機能も一通り入っているようです。

FrankenPHPをWebサーバーとして使う

WebサーバーでPHPを実行する場合、次のような組み合わせで使うことが多いと思います。

  • Apache + PHPモジュール + PHPファイル
  • Nginx + PHP-FPM + PHPファイル

FrankenPHPは前述のような特徴があるため、次のようなシンプルな組み合わせで実行可能です。

  • FrankenPHP + PHPファイル

それでいてFrankenPHPの公式サイトによるとFPMより3.5倍速いという記載があったり、Caddyの公式ページにはSwooleやRoadRunnerより4倍速いとあります。

3.5x faster than FPM

With FrankenPHP, Caddy acts as a PHP application server that delivers PHP pages about 4x faster than Swoole or RoadRunner: no need for php-fpm (FastCGI).

Webサーバーとして起動する場合、例えば次のようなコマンドで実行します。サーバーの設定は
Caddyfilephp.ini を使ってカスタマイズできます。

./frankenphp php-server

ソースを軽く読んだ感じ、処理の流れとしてはこんな感じでPHPファイルを実行しているようです。

Caddy(Go)
--> FrankenPHPModule(Go)
--> FrankenPHP(Go&PHP)
--> cgo(php_execute_script)
--> Zend Engine
--> PHPファイルを実行

FrankenPHPをCLIツールとして使う

CLIからPHPファイルを実行する場合、次のようなコマンドで実行できます。

./frankenphp php-cli /path/to/your/script.php

FrankenPHPをGoのパッケージとして使う

このページに沿って環境を整えれば、こんな感じでGoの中からPHPファイルを実行することもできそうです。が、軽く試した感じうまくできませんでした。時間切れなので今回はここで諦めます。

package main

import (
	"os"

	"github.com/dunglas/frankenphp"
)

func main() {
	const filePath = "test.php"
	f, _ := os.Create(filePath)
	defer f.Close()
	f.Write([]byte("<?php\n echo 'Hello, FrankenPHP!';"))
	os.Exit(frankenphp.ExecuteScriptCLI(filePath, []string{}))
}

既知の問題

このページにKnown Issuesがまとまっています。
上から適当にいくつかピックアップしますが、回避策などが提案されているのが良いですね。

  • GoのWebフレームワークFiberでクラッシュする(解決に向けて動いているっぽい)
  • PHP拡張機能 imap がサポートされていない(代替の拡張を推奨されている)
  • XDebug がクラッシュすることがある(解決に向けて動いているっぽい)
  • などなど

終わり

FrankenPHPについて軽くまとめてみました。かなり雑に調べたので間違っていることを書いているかもしれません。

以上です。

Discussion