PHP, with more certainty

Typed. Compiled.
Still PHP.

++PHP adds generics, typed locals and arrays, checked errors, and value-producing when expressions, then emits ordinary PHP for PHP 8.4+.

Apache 2.0 PHP 8.4+ output Composer-aware
Source stays yours. Build output stays readable.

The complete ++PHP language

More expressive before runtime

Express relationships that PHP tools can follow across your project, then deploy readable PHP through the workflow you already use.

Typed locals

Declare every local with one explicit, fixed type and initializer. Add readonly when its storage must not change.

Erased generics

Write reusable classes and callables with checked type parameters that compile to PHPDoc and ordinary PHP.

Typed arrays

Use array<T> for lists and array<K, V> for maps while keeping normal PHP array behavior at runtime.

when expressions

Produce one typed value from complete conditional branches with room for meaningful work in every branch.

Checked errors

Declare recoverable failures with throws and require every caller to catch or propagate them.

Mixed projects

Adopt ++PHP file by file. Check .php and .ppphp together, then build one complete PHP application.

Transparent compilation

What you write. What ships.

Generic relationships become conventional PHPDoc; typed arrays and when become ordinary PHP syntax. The result remains inspectable by your team and familiar to PHP tools. See how the language works

src/Box.ppphpyou write
<?php

class Box<T>
{
    function __construct(
        private T $value
    ) {}

    function get(): T
    {
        return $this->value;
    }
}

Money $total = when ($orders !== []) {
    Money $sum = Money::zero();
    foreach ($orders as $o) {
        $sum = $sum->plus($o->total());
    }
    return $sum;
} else {
    return Money::zero();
};
build/Box.phpppphp emits
<?php
declare(strict_types=1);

/** @template T */
class Box
{
    /** @param T $value */
    function __construct(
        private $value
    ) {}

    /** @return T */
    function get()
    {
        return $this->value;
    }
}

if ($orders !== []) {
    $__t1 = Money::zero();
    foreach ($orders as $o) {
        $__t1 = $__t1->plus($o->total());
    }
    $__w1 = $__t1;
} else {
    $__w1 = Money::zero();
}
$total = $__w1;

One compiler, three commands

Write, check, build.

Start with the boundary you choose. ++PHP can analyze the whole project, a directory, or one focused file without mutating source.

  1. init
    Prepare the projectCreate ppphp.json and prepare safe locations for generated PHP and temporary files.
  2. check
    Check your codeValidate the selected .ppphp and .php files together with the rest of the project.
  3. build
    Ship PHPWrite a complete PHP tree only after the selected project passes analysis.

Questions, answered

The PHP part stays familiar

Where does ++PHP code run?

The compiler produces ordinary PHP for PHP 8.4+ that runs with your Composer packages, extensions, web server, workers, and deployment tools.

Can I adopt it gradually?

Yes. .php and .ppphp files can live in the same source roots. Plain PHP participates in analysis and is copied into the build unchanged.

What happens to generics at runtime?

They are erased. The compiler checks each relationship, then emits deterministic PHPDoc that PHPStan, IDEs, and ordinary PHP consumers understand.

Does it understand Composer projects?

Yes. It follows Composer autoloading, installed packages, native PHP types, and PHPDoc while checking your project.

What is the license?

The compiler is open source under the Apache License 2.0.

Bring certainty to an existing codebase

Your project already speaks PHP.
Give it a stronger contract.

Begin with one .ppphp file, keep every dependency, and deploy the PHP you already know.