PHP's ease, with safety built in.

PHX keeps what made PHP productive — $variables, HTML templates, routing by file, save and reload — and makes the compiler responsible for type safety, safe output and speed.

Download 0.2.0 Read the specification

<?phx
import std.http.request;
import std.db.Database;

$name = request()->query("author") ?? "ann";   // ?string, narrowed by ??
$db = Database::open("data/blog.db");
$posts = $db->query(sql"SELECT title FROM posts WHERE author = {$name}");
?>
<h1>Posts by <?= $name ?></h1>
<ul>
<?phx foreach ($posts as $post): ?>
  <li><?= $post->string("title") ?? "untitled" ?></li>
<?phx endforeach; ?>
</ul>

Typed, without ceremony

A variable's type comes from its first assignment. No implicit conversions, strict ==, null safety with ?T, ?-> and ??, generics, interfaces and enums.

Escaping that knows where it is

Output is escaped automatically, and the compiler tracks the HTML around every <?= ?>. A string at the start of a URL, inside <script> or in an event handler is a compile error.

SQL without injection

Queries are sql"..." literals. Interpolated values always become bound parameters — there is no way to build SQL text from a string.

Locked down by default

A Content-Security-Policy with automatic nonces, CSRF checks, server-side sessions, rate limiting, and file access only where phx.toml allows it.

Fast

A typed register VM, a Cranelift JIT for numeric code, and a signed bytecode cache. fib(30) runs in about 7 ms.

Everything in one command

phx serve, test, fmt, lsp, install and migrate (from PHP), plus a VS Code extension.

Mistakes are compile errors

Escaping alone cannot make a URL safe: javascript:alert(1) contains nothing to escape. PHX knows the value lands at the start of an href and refuses to compile until it is checked.

<?phx
import std.http.request;
$site = request()->query("site") ?? "";
?>
<a href="<?= $site ?>">Website</a>
error: a URL attribute cannot start with an unchecked value
 --> profile.phx:5:14
  |
5 | <a href="<?= $site ?>">Website</a>
  |              ^^^^^
  = note: use `safe_url($url)`, which only allows http(s), mailto, tel and relative URLs (blocks `javascript:`); `escape()` does not make a URL safe

1 error found

Download

PHX 0.2.0 for Windows, Linux and macOS. Unpack the archive and put phx on your PATH.

Check the archive against SHA256SUMS from the same release, then run it:

sha256sum -c SHA256SUMS --ignore-missing
tar -xzf phx-0.2.0-x86_64-unknown-linux-gnu.tar.gz
./phx-0.2.0-x86_64-unknown-linux-gnu/phx --version
./phx-0.2.0-x86_64-unknown-linux-gnu/phx serve mysite   # http://127.0.0.1:8080

Or build from source with a recent stable Rust and a C compiler: cargo build --release.

For VS Code, install the extension from editors/vscode for highlighting and live diagnostics.

Security

PHX has been through three security audits, each followed by fixes and regression tests. Read the audit report. To report a vulnerability, email security@phx-lang.org.