The opinionated PHP code formatter powered by Go—think gofmt
, but for PHP.
TL;DR Run
phpfmt -w .
and stop arguing about code style.
Status Beta – already production-ready for many teams, but we still expect to receive reports of edge cases.
- Zero-config, one true style –
phpfmt
enforces a single canonical layout so you never waste time on bikeshedding. - Fast & memory-safe – written in Go, typically formats thousands of lines in a fraction of a second.
- Up-to-date PHP – full syntax support for PHP 5.6 → 8.4 (includes enums, attributes, readonly, etc.).
- Tabs over spaces – indentation is done with hard tabs only. (Yes, we know.)
- Neat column alignment – e.g., key ⇒ value array literals
or
const NAME = VALUE
blocks are aligned into tidy columns.
For now, the Go toolchain is required to install phpfmt
.
You do not need Go for anything other than the one-time installation.
If you don't have Go installed, follow the instructions on the official Go website.
Then, run the following command to install phpfmt
:
go install mibk.dev/phpfmt@latest
Format a specific file and write the result to standard output:
phpfmt [file.php]
Format and overwrite a file in-place:
phpfmt -w [file.php]
Format all PHP files in the current directory and its subdirectories:
phpfmt -w .
A hallmark feature of phpfmt
is that it uses whitespace to visually encode operator precedence.
Tight-binding operators are glued together; looser ones are padded with spaces.
This mirrors Go’s gofmt
and makes complex expressions readable at a glance—often surfacing subtle bugs.
-echo $x ** 3 * 4;
-$x = 3 + 4 * 5;
+echo $x**3 * 4;
+$x = 3 + 4*5;
// & binds tighter than |
-$x = $a | ($b ^ $c) & $d;
+$x = $a | ($b ^ $c)&$d;
Many codebases put a space after every unary !
—if (! $cond)
.
phpfmt
keeps the operator tight (!$cond
) everywhere
except when the operand starts with an instanceof
expression.
The extra space visually signals that instanceof
binds tighter than !
,
i.e. the code is parsed as !($expr instanceof Foo)
rather than (! $expr) instanceof Foo
.
-if(!$foo->name instanceof Foo\Id){
+if (! $foo->name instanceof Foo\Id) {
// ...
}
// The exponent operator has higher precedence than unary minus.
-$x = -$a ** 3;
+$x = - $a**3;
// Comparison binds tighter than XOR.
-if ($a^0x0F !== 0);
+if ($a ^ 0x0F!==0);
// === binds tighter than &.
-if ($dir->perm & 01 === 0);
+if ($dir->perm & 01===0);
// Logical || binds tighter than ??.
-$a || $b ?? (string) $c;
+$a||$b ?? (string)$c;
// But the keyword `and` is lower than ??.
-$a and $b ?? (string) $c;
+$a and $b??(string)$c;
phpfmt
is PHP version aware.
It automatically reads the required PHP version from composer.json
.
It adjusts formatting based on the PHP version,
especially for operator precedence changes and trailing commas.
For example, the .
operator's precedence changed in PHP 8.0.
In PHP 7.4, where .
and +
had the same precedence, phpfmt
outputs:
echo 'Sum: ' . $a + $b;
echo 'Shift: '.$a << 2;
For PHP 8.0, where both +
and <<
bind more tightly than .
,
phpfmt
adjusts the spacing to make this clear:
echo 'Sum: ' . $a+$b;
echo 'Shift: ' . $a<<2;
Project | Commit |
---|---|
Composer | 4abf4f90 |
PHPStan | a31cb411 |
Laravel | cfa7ef31 |
Doctrine | 9e31f713 |
Those commits were generated by running nothing more than phpfmt -w .
over the respective code-bases.
The style of phpfmt
is not set in stone—yet.
The goal of this project is to create a universal, standardized format for PHP files.
If you have a suggestion for a better style, we encourage you to submit a proposal.
Please open an issue to discuss your proposal.
phpfmt
is released under the MIT License.