Videos
Is this online PHP formatter free?
What does a PHP Formatter do?
Why do I need to select a PHP version?
I found three code formatters for PHP.
Prettier (With PHP Plugin)
PrettyPHP (https://github.com/lkrms/vscode-pretty-php)
phpfmt (https://github.com/kokororin/vscode-phpfmt)
I was able to setup Prettier with the PHP plugin but the setup is not ideal since I have to install prettier and the prettier PHP plugin from NPM into the project every single time which is not the case when using Prettier VSCode extension with HTML, JS and CSS. I do like how Prettier has its own configuration .prettierrc files and it allows you to set a standard format for a project you are collaborating with others, however I believe formatting should be done in the IDE such as using a VSCode extension and this is the case with the Prettier extension for HTML, JS and CSS but not for PHP since it requires NPM packages.
The other two do not look popular. Am I missing something? I would like to have a standard format or be able to have an opinionated format setup like Prettier for JS but for PHP.
you're right, there seems to be no indentation for HTML (others are also confused). XML works, even with loaded code.
<?php
function tidyHTML($buffer) {
// load our document into a DOM object
$dom = new DOMDocument();
// we want nice output
$dom->preserveWhiteSpace = false;
$dom->loadHTML($buffer);
$dom->formatOutput = true;
return($dom->saveHTML());
}
// start output buffering, using our nice
// callback function to format the output.
ob_start("tidyHTML");
?>
<html>
<head>
<title>foo bar</title><meta name="bar" value="foo"><body><h1>bar foo</h1><p>It's like comparing apples to oranges.</p></body></html>
<?php
// this will be called implicitly, but we'll
// call it manually to illustrate the point.
ob_end_flush();
?>
result:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>foo bar</title>
<meta name="bar" value="foo">
</head>
<body>
<h1>bar foo</h1>
<p>It's like comparing apples to oranges.</p>
</body>
</html>
the same with saveXML() ...
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>foo bar</title>
<meta name="bar" value="foo"/>
</head>
<body>
<h1>bar foo</h1>
<p>It's like comparing apples to oranges.</p>
</body>
</html>
probably forgot to set preserveWhiteSpace=false before loadHTML?
disclaimer: i stole most of the demo code from tyson clugg/php manual comments. lazy me.
UPDATE: i now remember some years ago i tried the same thing and ran into the same problem. i fixed this by applying a dirty workaround (wasn't performance critical): i just somehow converted around between SimpleXML and DOM until the problem vanished. i suppose the conversion got rid of those nodes. maybe load with dom, import with
simplexml_import_dom, then output the string, parse this with DOM again and then printed it pretty. as far as i remember this worked (but it was really slow).
The result:
<!DOCTYPE html>
<html>
<head>
<title>My website</title>
</head>
</html>
Please consider:
function indentContent($content, $tab="\t"){
$content = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $content); // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries)
$token = strtok($content, "\n"); // now indent the tags
$result = ''; // holds formatted version as it is built
$pad = 0; // initial indent
$matches = array(); // returns from preg_matches()
// scan each line and adjust indent based on opening/closing tags
while ($token !== false && strlen($token)>0){
$padPrev = $padPrev ?: $pad; // previous padding //Artis
$token = trim($token);
// test for the various tag states
if (preg_match('/.+<\/\w[^>]*>
token, $matches)){// 1. open and closing tags on same line - no change
$indent=0;
}elseif(preg_match('/^<\/\w/', $token, $matches)){// 2. closing tag - outdent now
indent>0) $indent=0;
}elseif(preg_match('/^<\w[^>]*[^\/]>.*
token, $matches)){// 3. opening tag - don't pad this one, only subsequent tags (only if it isn't a void tag)
foreach($matches as $m){
if (preg_match('/^<(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)/im', $m)){// Void elements according to http://www.htmlandcsswebdesign.com/articles/voidel.php
$voidTag=true;
break;
}
}
$indent = 1;
}else{// 4. no indentation needed
$indent = 0;
}
if ($token == "<textarea>") {
$line = str_pad($token, strlen($token) +
tab, STR_PAD_LEFT); // pad the line with the required number of leading spaces
$result .= $line; // add to the cumulative result, with linefeed
$token = strtok("\n"); // get the next token
indent; // update the pad size for subsequent lines
} elseif ($token == "</textarea>") {
$line = $token; // pad the line with the required number of leading spaces
$result .= $line . "\n"; // add to the cumulative result, with linefeed
$token = strtok("\n"); // get the next token
indent; // update the pad size for subsequent lines
} else {
$line = str_pad($token, strlen($token) +
tab, STR_PAD_LEFT); // pad the line with the required number of leading spaces
$result .= $line . "\n"; // add to the cumulative result, with linefeed
$token = strtok("\n"); // get the next token
indent; // update the pad size for subsequent lines
if ($voidTag) {
$voidTag = false;
$pad--;
}
}
}
return $result;
}
// $htmldoc is your DOMDocument Object!
$niceHTMLwithTABS = indentContent($htmldoc->saveHTML(), $tab="\t");
echo $niceHTMLwithTABS;
Will result in HTML that has:
- Indentation based on "levels"
- Line breaks after block level elements
- While inline and self-closing elements are not affected
The function (which is a method for class I use) is largely based on: https://stackoverflow.com/a/7840997/7646824
Update 2021-07-21
It's been more than half a decade since I first wrote this answer. The extensions to which I originally linked are abandoned, and Visual Studio Code's intrinsic PHP support hasn't improved, which is disappointing. The only decent extension still standing of which I'm aware is PHP Intelephense, which uses a freemium model: basic features are free, and a lifetime license is $12 USD as of writing.
The free version of Intelephense supports code formatting with the usual shortcuts (Alt + Shift + F on Windows and Linux, ⌥⇧F on macOS). Visual Studio Code continues to lack built-in support for PHP code formatting and will direct you to the extension marketplace if you attempt to format PHP without an appropriate extension installed.
Original answer
Visual Studio Code has pretty awesome PHP support. What it lacks is covered by extensions. A quick search reveals at least three (1, 2, and 3) that claim to support PHP formatting.
They mostly seem to use the standard shortcut of Alt + Shift + F on Windows/Linux, with varying shortcuts on Mac. If you're on Mac, give ⌥⇧F a try.
I installed
Prettier for HTML, CSS, and JavaScript files
PHP Intelephense for PHP files
I followed the instructions for each plugin but found I had to additionally edit settings.json manually in order to get them to work together.
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[php]": {
"editor.defaultFormatter": "bmewburn.vscode-intelephense-client"
}
The settings use Intelephense as the formatter for PHP files and use Prettier as the formatter for all other files.
Now I use Shift + Alt + F to format the files like everybody else.
I find some extensions format it but it still looks weird. What's the best and preferably one that formats on save?