Giter Site home page Giter Site logo

pretty-php's Introduction

pretty-php: the opinionated code formatter

pretty-php logo

Latest Stable Version License CI Status Code Coverage Visual Studio Marketplace install count Open VSX Registry download count


pretty-php is a fast, deterministic, minimally configurable code formatter for PHP.

By taking responsibility for the whitespace in your code, pretty-php makes it easier to focus on the content, providing time and mental energy savings that accrue over time.

Code formatted by pretty-php produces the smallest diffs possible and looks the same regardless of the project you're working on, eliminating visual dissonance and improving the speed and effectiveness of code review.

You can use pretty-php as a standalone tool, run it from your editor, pair it with a linter, or add it to your CI workflows. Configuration is optional in each case.

If you have questions or feedback, I'd love to hear from you.

pretty-php isn't stable yet, so updates may introduce formatting changes that affect your code.

Features

  • Supports code written for PHP 8.3 and below (when running on a PHP version that can parse it)
  • Code is formatted for readability, consistency and small diffs
  • With few exceptions, previous formatting is ignored, and nothing in the original file other than whitespace is changed
  • Entire files are formatted in place
  • Formatting options are deliberately limited (pretty-php is opinionated so you don't have to be)
  • Configuration via a simple JSON file is supported but not required
  • PHP's embedded tokenizer is used to parse input and validate output
  • Formatted and original code are compared for equivalence
  • Output is optionally compliant with PSR-12 and PER (details here)

Installation

Requirements

  • Linux, macOS or Windows
  • PHP 8.3, 8.2, 8.1, 8.0 or 7.4 with the standard tokenizer, mbstring and json extensions enabled

PHP archive (PHAR)

pretty-php is distributed as a PHP archive you can download and run:

wget -O pretty-php.phar https://github.com/lkrms/pretty-php/releases/latest/download/pretty-php.phar
php pretty-php.phar --version

The PHAR can be made executable:

chmod +x pretty-php.phar
./pretty-php.phar --version

Official releases distributed via GitHub are signed and can be verified as follows:

wget -O pretty-php.phar https://github.com/lkrms/pretty-php/releases/latest/download/pretty-php.phar
wget -O pretty-php.phar.asc https://github.com/lkrms/pretty-php/releases/latest/download/pretty-php.phar.asc
gpg --recv-keys 0xE8CC5BC780B581F2
gpg --verify pretty-php.phar.asc pretty-php.phar

Installation with PHIVE, which verifies PHAR releases automatically, is also supported:

phive install lkrms/pretty-php
./tools/pretty-php --version

Adding lkrms/pretty-php to your project as a Composer dependency is not recommended.

Arch Linux

Arch Linux users can install pretty-php from the AUR. For example, if your preferred AUR helper is yay:

yay -S pretty-php

macOS

Homebrew users on macOS can install pretty-php using the following command, which automatically taps lkrms/misc if necessary:

brew install lkrms/misc/pretty-php

Usage

Once installed, getting started with pretty-php is as simple as giving it something to format. For example, to format bootstrap.php and any PHP files in the src directory:

pretty-php bootstrap.php src

To see what would change without actually replacing any files, add the --diff option:

pretty-php --diff bootstrap.php src

For detailed usage information, see usage or run:

pretty-php --help

Editor integrations

Pragmatism

pretty-php generally abides by its own rules ("previous formatting is ignored, and nothing in the original file other than whitespace is changed"), but exceptions are occasionally made and documented here.

  • Newlines are preserved
    Line breaks adjacent to most operators, delimiters and brackets are copied from the input to the output.

    Use -N/--ignore-newlines to disable this behaviour.

  • Strings and numbers are normalised
    Single-quoted strings are preferred unless the alternative is shorter or backslash escapes are required.

    Use -S/--no-simplify-strings and -n/--no-simplify-numbers to disable or modify this behaviour.

  • Alias/import statements are grouped and sorted alphabetically
    Use -M/--no-sort-imports or -m/--sort-imports-by to disable or modify this behaviour.

  • Comments are moved if necessary for correct placement of adjacent tokens
    Relocated DocBlocks are converted to standard C-style comments as a precaution.

    Use --disable=move-comments to disable this behaviour.

  • Comments beside code are not moved to the next line

  • Comments are trimmed and aligned

  • Empty DocBlocks are removed

License

MIT

pretty-php's People

Contributors

lkrms avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

pretty-php's Issues

Add support for formatting-related requirements of PSR-12

PrettyPHP's default formatting is largely PSR-12 compliant, but there are some differences to address.

Parts of PSR-12, e.g. PascalCase class names, fall outside the scope of a formatter and won't be implemented, although exceptions are sometimes made (use import statements are already sorted by default, for example).

  • LF line endings
  • Indent of 4 spaces
  • Line length "SHOULD NOT" exceed 80 characters and "MUST" have a soft limit of 120 characters
  • One statement per line (PreserveOneLineStatements must not be enabled)
  • Blank lines after "header blocks" (SpaceDeclarations and SortImports mandatory):
    • <?php
    • file-level docblock (blank line only applied before namespace currently)
    • declare statements
    • namespace declaration
    • class use statements
    • function use statements
    • constant use statements
  • Allow breaking over multiple lines if every item is on its own line (NoMixedLists mandatory):
    • implements and extends interfaces
      • Trigger if a newline appears after implements or extends, not just between first two interfaces
      • Add a newline before the opening brace of an anonymous class with an interface list that wraps
    • Parameters in function declarations
    • Variables in anonymous function use declarations
    • Arguments in function calls
    • Statements in for loops
  • One-line declare at line 1 of files also containing markup: <?php declare(strict_types=1) ?>
    • Suppress newline before close tag even if present in source
  • Force newlines before and after control structure expressions split over multiple lines
  • Add whitespace between exception types in catch
  • Enforce newline before first method in multiline method chains

exit

<?php

exit();
die();

Incorrectly changes to:

<?php

exit ();
die ();

Review `AlignData`

  • Improve documentation to clarify why tokens are eligible or ineligible for alignment
  • Optimize for performance
  • Test "relaxed" mode with a view to surfacing more specific controls for presets, or (preferably) improving default behaviour so it can be removed

if else alignment

Is there a way to turn this:

if (CODE) {
        // code
    } else
        if (CODE) {
            // code
        } else
            if (CODE) {
                // code
            }

into this:

if (CODE) {
  // code
} else if (CODE) {
  // code
} else if (CODE) {
  // code
}

Fix ternary / coalesce operator edge case

The last colon here should not be indented:

<?php

$threshold =
    $this->UncertaintyThreshold === null
        ? null
        : (is_array($this->UncertaintyThreshold)
            ? $this->UncertaintyThreshold[$algorithm] ?? null
                : $this->UncertaintyThreshold);

Fix hanging indentation regression

PrettyPHP v0.4.16 produces this:

<?php
class A
{
    private $b;

    protected function c()
    {
        return $this->b
            ?? ($this->b = implode(
                ':', ['a',
                    'b',
                            'c',
                        'd',
                    'e']
            ));
    }
}

Instead of this:

<?php
class A
{
    private $b;

    protected function c()
    {
        return $this->b
            ?? ($this->b = implode(
                ':', ['a',
                    'b',
                    'c',
                    'd',
                    'e']
            ));
    }
}

Document "hanging" vs "overhanging" indentation

A rough starting point:

.OH. is applied if:

  • the open bracket of the block is not followed by a newline, AND
  • either:
    • the block contains ,- or ;- delimited items, OR

    • the block forms part of a structure that continues, e.g.

      if ($block) {
          // continuation
      }
      1. Standard indentation is sufficient
      
      [
          ___, ___,
          ___, ___
      ]
      
      2. One level of hanging indentation is required
      
      [
          ___, ___
          .hh.___, ___,
          ___, ___
      ]
      
      3. One level of hanging indentation is sufficient
      
      [___, ___,
      .hh.___, ___]
      
      4. Two levels of hanging indentation are required
      
      [___, ___
      .hh..OH.___, ___,
      .hh.___, ___]
      
      5a. Two levels of hanging indentation are required per level of nesting
      
      [___, [___,
      .hh..OH..hh.___],
      .hh.___,[___, ___
      .hh..OH..hh..OH.___,
      .hh..OH..hh.___]]
      
      5b.
      
      [[[___
      .hh..OH..hh..OH..hh..OH.___,
      .hh..OH..hh..OH..hh.___],
      .hh..OH..hh.___],
      .hh.___]
      

Enum "//" comments have extra indentation

Before:

<?php
enum ExampleEnum {
    /**
     * Note.
     */
    case Foo;
    # Note.
    case Bar;
    // Note.
    case Qux;
}

After:

<?php
enum ExampleEnum
{
    /** Note. */
    case Foo;
        // Note.
    case Bar;
        // Note.
    case Qux;
}

Double spaces before comments on the end of the code line

pretty-php adds 2 spaces before the comment. expected 1.
Not sure if this is intentional, but I've never seen this style before.

<?php

class Example
{
    public int $test = 0;  // This is a test.

    public function example()
    {
        $this->test = 1;  // This is a test.
    }
}

blank line needed at start of file?

Hi there, thanks for pretty-php

I was running it (downloaded .phar version) over a project and ran into the following when it was trying to process a particular file:

Call to a member function declarationParts() on bool in phar:///usr/local/bin/pretty-php/src/Rule/DeclarationSpacing.php:218

Unfortunately I can't show you the code, but I can give you a close approximation of the first few lines of the file (no blank lines, no comments immediately after opening php tag):

<?php
date_default_timezone_set("Relevant/Timezone");
global $bad_practice;
define('SOME_VAR', 42);
/**
 * comment
 */
class SomeClass {
 ...

I did some messing around and found that I was able to work around this by inserting some blank lines at the start of the file, thusly:

<?php


date_default_timezone_set("Relevant/Timezone");
...

Hope this helps someone! :)

Align one-line switch cases?

For example:

switch ($operator) {
  default:
  case '=':
  case '==':  return $retrieved == $value;
  case '!=':
  case '<>':  return $retrieved != $value;
  case '<':   return $retrieved < $value;
  case '>':   return $retrieved > $value;
  case '<=':  return $retrieved <= $value;
  case '>=':  return $retrieved >= $value;
  case '===': return $retrieved === $value;
  case '!==': return $retrieved !== $value;
  case '<=>': return $retrieved <=> $value;
}

Preserve escaped carriage returns in multiline strings

e.g.

<?php
$string = "\rText after carriage return";
$string = "\rMultiline text after carriage return
";

Becomes:

<?php
$string = "\rText after carriage return";
$string = '
Multiline text after carriage return
';

Improve hanging indentation

For example, the hanging indentation here is unnecessary:

<?php
final class ErrorHandler
{
    private const FATAL_ERRORS =
        E_ERROR
            | E_PARSE
            | E_CORE_ERROR
            | E_CORE_WARNING
            | E_COMPILE_ERROR
            | E_COMPILE_WARNING;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.