PHP's ease, with safety built in.

PHV 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.3.0 Read the specification

<?phv
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>
<?phv foreach ($posts as $post): ?>
  <li><?= $post->string("title") ?? "untitled" ?></li>
<?phv 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 phv.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

phv 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. PHV knows the value lands at the start of an href and refuses to compile until it is checked.

<?phv
import std.http.request;
$site = request()->query("site") ?? "";
?>
<a href="<?= $site ?>">Website</a>
error: a URL attribute cannot start with an unchecked value
 --> profile.phv: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

PHV 0.3.0 for Windows, Linux and macOS. Unpack the archive and put phv on your PATH.

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

sha256sum -c SHA256SUMS --ignore-missing
tar -xzf phv-0.3.0-x86_64-unknown-linux-gnu.tar.gz
./phv-0.3.0-x86_64-unknown-linux-gnu/phv --version
./phv-0.3.0-x86_64-unknown-linux-gnu/phv 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 PHV Language from the Marketplace (code --install-extension phv-lang.phv-language) for highlighting and live diagnostics. It is also attached to each release as phv-0.3.0.vsix.

Security

PHV has been through three security audits, each followed by fixes and regression tests. Read the audit report. To report a vulnerability, email [email protected].