Christopher Pitt

Prettier PHP Code

I'm sick and tired of having to research how to do this, every time I set up a new machine. So, I'm writing this for me as much as I'm writing it for you. I'm going to show you a couple tips for displaying and formatting PHP code, in VSCode...

New extensions for existing languages

If you've ever connected a repo to some CI service, you've probably encountered a proprietary config file. I write a bunch of preprocessed PHP code, so I'm always opening up .pre files. VSCode doesn't always understand the appropriate language to open, when it encounters an unpopular file extension.

If you'd like to associate a new file extension with an existing language, you can add the following code to your config file:

"files.associations": {
    "*.pre": "php"
}

The left-hand side is a regex for the files you want to associate, and the right-hand side is the language you'd like to associate them with. You can find more details (unhelpfully located) at https://code.visualstudio.com/docs/languages/identifiers.

You can associate multiple patterns with the same language, so go wild.

Formatting PHP code

If you're a firm adherent to PSR-2/12, this next bit won't be that useful to you. I have been using Prettier to format my code, because it is easy to use and integrates with everything in JS-land. It's a little less common seeing it used in PHP projects, but here goes...

Run this:

npm install --save-dev prettier @prettier/plugin-php

Then, define a new script in your package.json file:

"scripts": {
    "format:php": "prettier --config=prettier.config.js --write --parser=php"
}

You can use the defaults, or you can also define your own config file. This is what my prettier.config.js file looks like:

(module.exports = {
    "printWidth": 120,
    "tabWidth": 4,
    "useTabs": false,
    "semi": false,
    "singleQuote": false,
    "trailingComma": "all",
    "bracketSpacing": true,
    "jsxBracketSameLine": false,
    "arrowParens": "avoid",
    "proseWrap": "never"
})

You could put the parser: "php" part in config (instead of the script), but then JS code in the same project wouldn't be formatted using the same settings.

You can use the script like this:

npm run format:php ./source/**/*.pre

...where ./source/**/*.pre is a regex for the files you want to process. Prettier will tell you if it couldn't find any matching files. It'll also tell you which files it couldn't format (usually due to syntax errors). Many of my preprocessed files include syntax that PHP doesn't support, so I get diminishing returns, there.

Formatting code on save

If your formatting depends on running a script, you probably won't use it much. That is, unless you set up a Git hook to run it before making commits. That's not a bad strategy...

Instead, I want VSCode to format a file every time I save it. To do that, we need to set up a custom task. I'll show you what and where that file is supposed to be, but you can have VSCode create a new file by following these steps:

  1. Open the command palette. On macOS, this is done using shift + command + p.
  2. Select "Tasks: Configure Task"
  3. Select "Other"

You'll be taken to a new tasks.json file, in the .vscode folder.

There are a few things you can configure ab out a task:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Run tests",
            "type": "shell",
            "command": "./scripts/test.sh",
            "windows": {
                "command": ".\\scripts\\test.cmd"
            },
            "group": "test",
            "presentation": {
                "reveal": "always",
                "panel": "new"
            }
        }
    ]
}

I only care about running my task on macOS (since that's what all my dev machines are running), so it looks like this:

{
    "tasks": [
        {
            "label": "Format PHP",
            "type": "shell",
            "command": "npm run format:php ${file}",
            "presentation": {
                "reveal": "never"
            },
            "problemMatcher": []
        }
    ]
}

Now, when I open the command palette, and go to "Tasks: Run Task"; I see "Format PHP" as an option. I can run the task and it'll format the current file. There are more docs, if you can't get your task running the way you want.

Finally, we need a way for this task to be run whenever we save. I installed an extension that will run tasks by label, for matching extensions. I just needed to add the following to config:

{
    "triggerTaskOnSave.tasks": {
        "Format PHP": ["**/*.php", "**/*.pre"]
    }
}

Now, when I have a .php or .pre file open, and I save it, that NPM script will be run!

Would you like me to keep you in the loop?

I write about all sorts of interesting code things, and I'd love to share them with you. I will only send you updates from the blog, and will not share your email address with anyone.