Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PSR-1 Coding Style Guide (multi-chapter) #15

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
af71f89
add a fleshed-out version of style guide proposal
Mar 6, 2012
69be98c
Minor Spelling corrections
saltybeagle Mar 6, 2012
550dc72
Merge pull request #1 from saltybeagle/master
Mar 6, 2012
0335b99
break lines at about 80 chars
Mar 7, 2012
7bb84cd
merge spelling changes
Mar 7, 2012
49b6fef
update line length notes per Andreas Moller and Wil Moore
Mar 8, 2012
c36244b
add a note about namespace names, and change so that there is one 'us…
Mar 8, 2012
5aa80a2
add a note about namespace names, and change so that there is one 'us…
Mar 8, 2012
3c5dea0
Merge branch 'master' of github.com:pmjones/fig-standards
Mar 8, 2012
aecd965
use namespaced constants, per @KingCrunch, and only use globals const…
Mar 8, 2012
93e6c5b
per notes from @gnugat and Wil Moore III, discourage global vars inst…
Mar 8, 2012
9cd5072
per notes from @KingCrunch and @klaussilveira, reducing the errors ch…
Mar 8, 2012
c6a7158
add try/catch to the control structures
Mar 8, 2012
336336b
rename the chapter
Mar 8, 2012
97003b0
add a comma
Mar 8, 2012
c775d79
minor changes
Mar 8, 2012
aac843f
update the 'credits'
Mar 8, 2012
d4b4c3d
add note about trailing space
Mar 8, 2012
fa5e0ba
discourage, but allow, global functions
Mar 8, 2012
ee14d0b
extract operator and expression rules to their own chapter
Mar 8, 2012
e977d3e
add <?php lines
Mar 8, 2012
41c3ae5
minor updates
Mar 8, 2012
e2bb63d
break into sections, add a note about blank lines
Mar 8, 2012
214b6a3
rewording
Mar 8, 2012
9412f14
rewording
Mar 8, 2012
cad7314
rewording
Mar 8, 2012
f51cce2
include a reference to &$args
Mar 8, 2012
67af4d0
fix a merge conflict, and some rewording
Mar 8, 2012
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 21 additions & 0 deletions proposed/psr-1-coding-style-guide/0000-preamble.md
@@ -0,0 +1,21 @@
Preamble
========

The goal for this guide is to increase consistency in style across disparate
PHP projects written by multiple authors. It is intended to serve as a
reference for reasonable expectations so as to reduce cognitive friction when
scanning code from different projects.

This style guide is not a moral or ethical statement. It is an attempt to
agree upon a common set of rules, requirements, recommendations, idioms, and
approaches for code formatting. Any such guide is by nature arbitrary. The
benefit is in the adherence to the rules, not in the rules themselves.

There are times when a particular rule or recommendation will not make sense
in a particular limited context. Breaking the rule or recommendation in that
particular limited context does not mean the remainder of the codebase under
consideration is not PSR-1 compliant; instead, it is to be recognized as a
regrettable but necessary departure from the guide for that one circumstance.

This guide is derived from commonalities between Horde, PEAR, Solar, Symfony,
Zend, and other projects.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Zend Framework or ZF.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call.

9 changes: 9 additions & 0 deletions proposed/psr-1-coding-style-guide/0100-php-tags.md
@@ -0,0 +1,9 @@
PHP Tags
========

Use the long `<?php ?>` tags for PHP code. Use of short-echo `<?= ?>` tags is
also allowed. Do not use the other tag variations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


Cf. <http://php.net/manual/en/language.basic-syntax.phpmode.php>

In files that contain only PHP, leave out the closing PHP tag.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -0,0 +1,45 @@
Indenting and Line Length
=========================

Indenting
---------

Use an indent of 4 spaces. Do not use tabs. The use of spaces helps to avoid
problems with diffs, patches, history, and annotations, and provides
fine-grained sub-indentation when aligning elements on consecutive lines.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


Line Length
-----------

Lines should be limited to 75-85 characters in length. This is based on known
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure this is good for code. This particular limit was popular when screen sizes were smaller, but now screens and resolutions are much bigger and 100 quite acceptable. This is something that is more appropriate for text files (like markdown or rst).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Horde, PEAR, Solar, Symfony, Zend, Lithium, et al. all note 80 characters as the expected line length (in some cases it's a soft limit, but it's still mentioned). Per comments elsewhere, screen size and resolution are not the driving factor; human cognitive limitations are.

human cognitive limitations, not the technical limitations of screen windows
or text editors. When necessary, it is allowed to split a single statement
across subsequent lines, per rules noted elsewhere in this guide.

Some further insight into the 75-85 characters rule:

> How many words per line can a person scan, and still be able to grasp the
> content of the line in the context of the surrounding lines? Printing and
> publishing typographers figured out a long time ago that most people can
> read no more than 10 to 12 words per line before they have trouble
> differentiating lines from each other. (A “word” is counted as five
> characters on average.) Even allowing for a 25% to 50% increase, that
> brings us up to 15 words. Times 5 characters per word, that means 75
> characters on a line.
>
> So the style guide limitation on line length is not exactly arbitrary. It
> is about the developer’s ability to effectively scan and comprehend
> strings of text, not about the technical considerations of terminals and
> text-editors.

-- "Line Length, Volume, and Density"
<http://paul-m-jones.com/archives/276>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍



Other Considerations
--------------------

Code blocks may have as many blank lines as needed to increase readability
and comprehension.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


Do not add trailing spaces at the end of lines.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -0,0 +1,54 @@
`namespace`, `use`, and `class`
===============================

All namespaces and classes should be named with PSR-0 in mind. This means each
class should be in a file by itself, and should be in a namespace of at least
two levels: a top-level vendor name, and a second-level package name within
that vendor.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not right. As far as I know the second level namespace is not enforced by PSR-0, and many many libs out there just have a vendor name namespace containing core classes. The key thing is that you don't have anything in the global namespace to avoid collisions & improve autoload-ability with prefixes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, you're right. All the examples have Vendor\Package, but the actual "Mandatory" bullet point only says "Vendor." Good catch!


Class names are always in `StudlyCase`. The class declaration should have one
empty line above it. The opening and closing braces for the class go on their
own line.

<?php
namespace Vendor\Package;

class ClassName
{
// constants, properties, methods
}

The `use` declarations go immediately after the namespace declaration with no
line separating them. There should be one `use` keyword per declaration.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why shouldn't it be no lines separating them ? It may improve readability to regroup the use by vendor name, separated by a line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@clemherreman Others have argued, and I now agree, that namespace, use, and class should all have a line of separation.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't say "should", but "may" :)


<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Makes a lot of sense to me (for the same reasons I propose wrapping of method call parameters and array initialization with a trailing comma on the last line before a line followed with );


class ClassName
{
// constants, properties, methods
}

The `extends` and `implements` keywords should be on the same line as the
class name. Lists of `implements` that exceed the line length limit may be
split across multiple lines, where each subsequent line is indented once.
List only one interface per line.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements
InterfaceName,
AnotherInterfaceName,
YetAnotherInterface,
InterfaceInterface
{
// constants, properties, methods
}

29 changes: 29 additions & 0 deletions proposed/psr-1-coding-style-guide/0400-constants.md
@@ -0,0 +1,29 @@
Constants
=========

The PHP keywords `true`, `false`, and `null` are all lower case all the time.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


All other user-defined constants are all upper case all the time, with
underscore separators.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


<?php
namespace Vendor\Package;

class ClassName
{
const CONSTANT_NAME = 'constant value';
}

Global constants are strongly discouraged. Instead, create namespaced
constants for the vendor and package:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


<?php
namespace Vendor\Package;
const CONSTANT_NAME = 'constant_value';

If a global constant is absolutely unavoidable, prefix it with the vendor and
package name:

<?php
define('VENDOR_PACKAGE_CONSTANT_NAME', 'constant_value');

@@ -0,0 +1,32 @@
Variable And Property Names
===========================

This guide expressly avoids any requirement regarding the use of
`$StudlyCase`, `$camelCase`, or `$under_score` variable and property names. It
is often the case that variable names map directly field names in external
data sources. Changing between naming conventions when changing contexts
merely to suit a style guide would be counterproductive in such cases.

Some projects prefix property names with a single underscore to indicate a
protected or private visibility. This guide discourages but does not disallow
that practice.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


Whatever naming convention is used should be applied consistently within a
reasonable scope. That scope may be vendor-level, package-level, class-level,
or function-level.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


Class properties should explicitly note the visibility keyword.

<?php
namespace Vendor\Package;

class ClassName
{
public $property = null;
}

Global variables are strongly discouraged. If a global variable is absolutely
unavoidable, it should be prefixed with the vendor and package name.

<?php
$Vendor_Package_VariableName = 'variable_value';
@@ -0,0 +1,86 @@
Variable and Property Assignment
================================

Single Assignment
-----------------

Assignment looks like the following.

$foo = 'value';

To support readability, contiguous assignments may be aligned on the equals
sign:

$short = fooBar($baz);
$longer = dibGir($zim);


Multi-Line Assignment
---------------------

Assignments may be split onto several lines when the line length limit is
exceeded. The equals sign has to be positioned onto the following line, and
indented once.

$this->longArrayPropertyName[$this->someOtherPropertyValue]
= $object->getFunctionResult(ClassName::CONSTANT_VALUE);

Similarly, when concatenating strings across multiple lines, align the dot
operator with the equals:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether that's a great idea, Paul. I've done this in the past, too, and I liked it a lot, but when you start refactoring code it requires you to shift around a lot of lines, and if in bad luck, it's not done with a few tabs (of course, interpreted as 4 spaces). What do you think about indenting concatenation with 4 spaces?

$foo = 'prefix_string '
    . $object->getSomeStringResult()
    . ' suffix string'
;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you suggest is what PEAR recommends, but ZF recommends aligning on the equals. After having used both, and after talking with others about it, we have found it easier when reading code to look down a single "column" of concatenation (i.e., when aligned on the equals). Does it cause editing troubles? Yes, but only when you change the length of the variable name. I think the tradeoff for aligning on equals is reasonable here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @pmjones, readability > writability.


$foo = 'prefix string '
. $object->getSomeStringResult()
. ' suffix string';

$bar .= 'prefix string '
. $object->getSomeStringResult()
. ' suffix string';


Ternary Assignment
------------------

Ternary assignments may be split onto subsequent lines when the exceed the
line length limit, or when the would be more readable. Align the question mark
and colon with the equals sign.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment.

$foo = ($expression1 && $expression2)
? $foo
: $bar;

$bar = ($expression3 && $expression4)
? $a_very_long_variable_name
: $bar;


Assignment By Reference
-----------------------

When assigning by reference, the `&` should be attached to the variable, not
the operator:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


// incorrect
$foo =& $bar;

// correct
$foo = &$bar;


Array Assignment
----------------

Array assignments may be split across subsequent lines if they would otherwise
break the line length limit, or if it would improve readability. They should be
indented once per array, and should be aligned on the `=>` double arrow. The
last value in each array should have a trailing comma; this is valid syntax
and reduces the chance of syntax violations when adding new elements.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Trailing comma.

Alignment with the =>arrow wastes some time with adding spaces that's otherwise spent more wisely. I'm also not sure whether readability is increased when you have (for other reasons) some really, really long array keys.


$an_array = [
'foo' => 'bar',
'subarray' => [
'baz' => 'dib',
'zim' => 'gir',
],
'irk' => 'doom',
];

@@ -0,0 +1,90 @@
Function And Method Declarations
================================

Function and method names are in `camelCase`.

Some projects prefix function and method names with a single underscore to
indicate a protected or private visibility. This guide discourages but does
not disallow that practice.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍



Functions
---------

A function declaration looks like the following. Note the placement of
parentheses, commas, spaces, and braces:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


<?php
namespace Vendor\Package;

function fooBarBaz($arg1, &$arg2, $arg3 = [], $arg4 = null)
{
// function body
}

This guide encourages using static class methods rather than functions; doing
so helps to support autoloading.

Global functions are strongly discouraged. If a global function is
unavoidable, prefix it with the vendor and package name.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

I believe that it's always avoidable, as it could be refactored into a static method of a FooUtils class, for example.


<?php
function Vendor_Package_FunctionName()
{
// function body
}


Methods
-------

Class methods are always be prefixed with an explicit visibility keyword:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


<?php
public function fooBarBaz($arg1, &$arg2, $arg3 = [], $arg4 = null)
{
// function body
}

Static methods always have the `static` keyword before the visibility keyword:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've always felt visibility is of higher importance, therefore I suggest to have the static keyword follow the visibility keyword.

On the other hand, it's not something I couldn't get used too.


<?php
static public function fooBarBaz($arg1, &$arg2, $arg3 = [], $arg4 = null)
{
// function body
}


Arguments
---------

Arguments with default values always go at the end of the argument list.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


Argument lists that exceed the line length limit may be split across
subsequent indented lines. There is only one argument per line. The closing
parenthesis and opening brace are placed together on their own line.

<?php
static public function fooBarBaz(
ClassTypeHint $arg1,
&$arg2,
array $arg3 = [],
$arg4 = null
) {
// function body
}

Anonymous Functions and Closures
--------------------------------

Declaration of anonymous functions looks like this; note the placement of
parentheses, commas, spaces and braces:

$foo = function ($bar, $baz) use ($zim, $gir) {
// body of the function
};

This is a departure from the "normal" function and method declaration. Because
`function` is a keyword, it gets a space after it; the same is true for `use`.
The opening brace goes on the same line as the declaration; the body is
indented once; and the closing brace goes on its own outdented line.