PHP-FIG PSR WTF

Steve Lacey


Ruby, PHP & JS dev at Simpleweb

Symfony1&2, Composer, Rails, T/BDD,
Zend1, WordPress



PHP Framework Interoperability Group


The idea behind the group is for project representatives to talk about the commonalities between our projects and find ways we can work together. Our main audience is each other, but we’re very aware that the rest of the PHP community is watching. If other folks want to adopt what we’re doing they are welcome to do so, but that is not the aim.


php-fig.org

Member projects

?

 Some notable voters


Phil Sturgeon @philsturgeon
PyroCMS
Kris Wallsmith @kriswallsmith
Assetic & Buzz
Bernhard Schussek @webmozart
Symfony2
Jordi Boggiano @seldaek
Composer & Packagist

Larry Garfield
@crell
Drupal

Cal Evans
@calevans
PHP Community

Voting on


Proposed Standards Recommendation (PSR)

New members

Bylaws

Proposed Standards Recommendations (PSRs)


A PSR is an attempt to standardise the way people use PHP in the hope that different frameworks and libraries will work better together.

Workflow


  • Pre-Draft
  • Draft
  • Review
  • Accepted

Accepted standards


The PHP-FIG has been around for 4 years, and it's produced 5 PSR's.

PSR-0 Autoloading
PSR-1 Basic coding standards
PSR-2 Coding style guide
PSR-3 Logger interface
PSR-4 Better autoloading

PSR-0: Autoloading Standard


Aims to provide a standard file, class and namespace convention to allow plug-and-play code.

A fully-qualified namespace and class
must have the following structure:


\<Vendor Name>\(<Namespace>\)*<Class Name>

Each namespace separator is converted to a

DIRECTORY_SEPARATOR when loading from the file system


Namespace Path
\Doctrine\Common\
IsolatedClassLoader
–> /path/to/project/lib/vendor/
Doctrine/Common/
IsolatedClassLoader.php
\Symfony\Core\Request –> /path/to/project/lib/vendor/
Symfony/Core/Request.php

The fully-qualified namespace and class is suffixed with .php when loading from the file system.

Each _ character in the CLASS NAME is converted to a DIRECTORY_SEPARATOR. The _ character has no special meaning in the namespace


Faux namespace Path
Zend_View_Helper_FormCheckbox /path/to/project/lib/vendor/
Zend/View/Helper/
FormCheckbox.php

Backwards compatible

  • Supports older projects with less legwork
  • Allows libraries to continue supporting <=5.2

PSR-0 defines the rules an autoloader must follow

as opposed to how the autoloader should be written

SplClassLoader is better though
...or you know, Composer

PSR-1: Basic Coding Standard


Aims to ensure a high level of technical interoperability between shared PHP code.

Overview

  • Files MUST use only <?php and <?= tags.
  • Files MUST use only UTF-8 without BOM for PHP code.
  • Files SHOULD either declare symbols (classes, functions, constants, etc.) or cause side-effects (e.g. generate output, change .ini settings, etc.) but SHOULD NOT do both.
  • Namespaces and classes MUST follow PSR-0.
  • Class names MUST be declared in StudlyCaps.
  • Class constants MUST be declared in all upper case with underscore separators.
  • Method names MUST be declared in camelCase.

PHP Tags


PHP code MUST use the long <?php ?> tags or the short-echo <?= ?> tags; it MUST NOT use the other tag variations.

Character Encoding


PHP code MUST use only UTF-8 without BOM.

Side Effects


A file SHOULD declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it SHOULD execute logic with side effects, but SHOULD NOT do both.


The phrase "side effects" means execution of logic not directly related to declaring classes, functions, constants, etc., merely from including the file.

While PSR-0 looks at basic "make sure it aint broke" interoperability, PSR-1 takes a slightly higher road and helps make sure that from the outside looking in, it all looks the same. Is this style guide? No. It means that a consistent interface can be kept for any components being used.


- Phil Sturgeon in the PHP-FIG mailing list

PSR-2: Coding Style Guide


Provides a Coding Style Guide for projects looking to standardise their code.

"PSR-2′s purpose is to have a single style guide for PHP code that results in uniformly formatted shared code."


phpcs --standard=PSR2 *.php


github.com/squizlabs/PHP_CodeSniffer


FILE: Tests/AllTests.php
--------------------------------------------------------------------------------
FOUND 2 ERROR(S) AFFECTING 2 LINE(S)
--------------------------------------------------------------------------------
  14 | ERROR | Expected 1 space after FUNCTION keyword; 0 found
 119 | ERROR | Each PHP statement must be on a line by itself
--------------------------------------------------------------------------------

FILE: Tests/ApiTest.php
--------------------------------------------------------------------------------
FOUND 2 ERROR(S) AND 1 WARNING(S) AFFECTING 2 LINE(S)
--------------------------------------------------------------------------------
 19 | ERROR   | Method name "ApiTest::ExampleApiCall" is not in camel caps format
 19 | WARNING | Line exceeds 120 characters; contains 126 characters
 21 | ERROR   | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
    |         | catch(...) {\n"
--------------------------------------------------------------------------------

FILE: Tests/AppTest.php
--------------------------------------------------------------------------------
FOUND 1 ERROR(S) AFFECTING 1 LINE(S)
--------------------------------------------------------------------------------
 33 | ERROR | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
    |       | catch(...) {\n"
--------------------------------------------------------------------------------

FILE: Tests/BillingTest.php
--------------------------------------------------------------------------------
FOUND 7 ERROR(S) AND 20 WARNING(S) AFFECTING 27 LINE(S)
--------------------------------------------------------------------------------
  56 | WARNING | Line exceeds 120 characters; contains 130 characters
  70 | ERROR   | Each PHP statement must be on a line by itself
  88 | WARNING | Line exceeds 120 characters; contains 130 characters
  91 | WARNING | Line exceeds 120 characters; contains 144 characters
  92 | WARNING | Line exceeds 120 characters; contains 143 characters
  93 | WARNING | Line exceeds 120 characters; contains 143 characters
  94 | WARNING | Line exceeds 120 characters; contains 144 characters
  95 | WARNING | Line exceeds 120 characters; contains 144 characters
  96 | WARNING | Line exceeds 120 characters; contains 144 characters
  97 | WARNING | Line exceeds 120 characters; contains 140 characters
  98 | WARNING | Line exceeds 120 characters; contains 142 characters
  99 | WARNING | Line exceeds 120 characters; contains 147 characters
 100 | WARNING | Line exceeds 120 characters; contains 144 characters
 101 | WARNING | Line exceeds 120 characters; contains 147 characters
 102 | WARNING | Line exceeds 120 characters; contains 141 characters
 123 | ERROR   | Multi-line function call not indented correctly; expected 12
     |         | spaces but found 10
 153 | WARNING | Line exceeds 120 characters; contains 130 characters
 565 | WARNING | Line exceeds 120 characters; contains 122 characters
 573 | WARNING | Line exceeds 120 characters; contains 131 characters
 575 | WARNING | Line exceeds 120 characters; contains 130 characters
 593 | ERROR   | Expected "foreach (...) {\n"; found "foreach(...){\n"
 602 | ERROR   | Opening brace should be on a new line
 605 | WARNING | Line exceeds 120 characters; contains 131 characters
 608 | WARNING | Line exceeds 120 characters; contains 131 characters
 617 | ERROR   | Opening brace should be on a new line
 635 | ERROR   | Opening brace should be on a new line
 658 | ERROR   | The closing brace for the class must go on the next line after
     |         | the body
--------------------------------------------------------------------------------

FILE: Tests/ContactTest.php
--------------------------------------------------------------------------------
FOUND 21 ERROR(S) AND 11 WARNING(S) AFFECTING 32 LINE(S)
--------------------------------------------------------------------------------
  256 | WARNING | Line exceeds 120 characters; contains 123 characters
  327 | WARNING | Line exceeds 120 characters; contains 149 characters
  336 | WARNING | Line exceeds 120 characters; contains 149 characters
  339 | WARNING | Line exceeds 120 characters; contains 142 characters
  350 | ERROR   | Expected "foreach (...) {\n"; found "foreach(...) {\n"
  363 | WARNING | Line exceeds 120 characters; contains 123 characters
  407 | WARNING | Line exceeds 120 characters; contains 142 characters
  417 | ERROR   | Expected "foreach (...) {\n"; found "foreach(...) {\n"
  459 | WARNING | Line exceeds 120 characters; contains 149 characters
  464 | WARNING | Line exceeds 120 characters; contains 123 characters
  468 | WARNING | Line exceeds 120 characters; contains 149 characters
  471 | WARNING | Line exceeds 120 characters; contains 146 characters
  536 | ERROR   | No space found after comma in function call
  575 | ERROR   | No space found after comma in function call
  582 | ERROR   | No space found after comma in function call
  595 | ERROR   | No space found after comma in function call
  608 | ERROR   | No space found after comma in function call
  628 | ERROR   | No space found after comma in function call
  635 | ERROR   | No space found after comma in function call
  636 | ERROR   | No space found after comma in function call
  645 | ERROR   | No space found after comma in function call
  646 | ERROR   | No space found after comma in function call
  652 | ERROR   | No space found after comma in function call
  653 | ERROR   | No space found after comma in function call
  672 | ERROR   | No space found after comma in function call
  674 | ERROR   | No space found after comma in function call
  707 | ERROR   | No space found after comma in function call
  711 | ERROR   | No space found after comma in function call
  712 | ERROR   | No space found after comma in function call
  719 | ERROR   | No space found after comma in function call
  739 | ERROR   | No space found after comma in function call
 1055 | WARNING | Line exceeds 120 characters; contains 177 characters
--------------------------------------------------------------------------------

FILE: Tests/GeneralTest.php
--------------------------------------------------------------------------------
FOUND 15 ERROR(S) AND 1 WARNING(S) AFFECTING 16 LINE(S)
--------------------------------------------------------------------------------
 50 | ERROR   | Multi-line function call not indented correctly; expected 12
    |         | spaces but found 10
 51 | ERROR   | Multi-line function call not indented correctly; expected 12
    |         | spaces but found 10
 52 | ERROR   | Multi-line function call not indented correctly; expected 12
    |         | spaces but found 10
 53 | ERROR   | Multi-line function call not indented correctly; expected 12
    |         | spaces but found 10
 54 | ERROR   | Multi-line function call not indented correctly; expected 12
    |         | spaces but found 10
 55 | ERROR   | Multi-line function call not indented correctly; expected 12
    |         | spaces but found 10
 56 | ERROR   | Multi-line function call not indented correctly; expected 12
    |         | spaces but found 10
 64 | ERROR   | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
    |         | catch(...) {\n"
 66 | ERROR   | Multi-line function call not indented correctly; expected 16
    |         | spaces but found 14
 67 | ERROR   | Multi-line function call not indented correctly; expected 16
    |         | spaces but found 14
 68 | ERROR   | Multi-line function call not indented correctly; expected 16
    |         | spaces but found 14
 69 | ERROR   | Multi-line function call not indented correctly; expected 16
    |         | spaces but found 14
 70 | ERROR   | Multi-line function call not indented correctly; expected 16
    |         | spaces but found 14
 71 | ERROR   | Multi-line function call not indented correctly; expected 16
    |         | spaces but found 14
 72 | ERROR   | Multi-line function call not indented correctly; expected 16
    |         | spaces but found 14
 76 | WARNING | Line exceeds 120 characters; contains 153 characters
--------------------------------------------------------------------------------

FILE: Tests/SpaceTest.php
--------------------------------------------------------------------------------
FOUND 6 ERROR(S) AND 5 WARNING(S) AFFECTING 8 LINE(S)
--------------------------------------------------------------------------------
  43 | WARNING | Line exceeds 120 characters; contains 122 characters
  45 | WARNING | Line exceeds 120 characters; contains 123 characters
  48 | WARNING | Line exceeds 120 characters; contains 123 characters
  51 | WARNING | Line exceeds 120 characters; contains 129 characters
 258 | ERROR   | Expected 1 space after FUNCTION keyword; 0 found
 265 | ERROR   | No space found after comma in function call
 265 | ERROR   | No space found after comma in function call
 265 | ERROR   | No space found after comma in function call
 265 | ERROR   | No space found after comma in function call
 285 | ERROR   | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
     |         | catch(...) {\n"
 289 | WARNING | Line exceeds 120 characters; contains 148 characters
--------------------------------------------------------------------------------

FILE: Tests/UserTest.php
--------------------------------------------------------------------------------
FOUND 9 ERROR(S) AND 3 WARNING(S) AFFECTING 12 LINE(S)
--------------------------------------------------------------------------------
  33 | ERROR   | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
     |         | catch(...) {\n"
  49 | ERROR   | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
     |         | catch(...) {\n"
  67 | ERROR   | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
     |         | catch(...) {\n"
  85 | ERROR   | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
     |         | catch(...) {\n"
 112 | WARNING | Line exceeds 120 characters; contains 129 characters
 118 | ERROR   | No space found after comma in function call
 122 | ERROR   | No space found after comma in function call
 126 | ERROR   | No space found after comma in function call
 139 | WARNING | Line exceeds 120 characters; contains 125 characters
 145 | ERROR   | Opening brace should be on a new line
 149 | ERROR   | Expected "try {\n...} catch (...) {\n"; found "try {\n...}
     |         | catch(...) {\n"
 153 | WARNING | Line exceeds 120 characters; contains 136 characters
--------------------------------------------------------------------------------

FILE: Tests/VCardTest.php
--------------------------------------------------------------------------------
FOUND 7 ERROR(S) AFFECTING 7 LINE(S)
--------------------------------------------------------------------------------
  77 | ERROR | Spaces must be used to indent lines; tabs are not allowed
  78 | ERROR | Spaces must be used to indent lines; tabs are not allowed
  79 | ERROR | Spaces must be used to indent lines; tabs are not allowed
  80 | ERROR | Spaces must be used to indent lines; tabs are not allowed
  81 | ERROR | Spaces must be used to indent lines; tabs are not allowed
  82 | ERROR | Spaces must be used to indent lines; tabs are not allowed
 407 | ERROR | Opening brace should be on a new line
--------------------------------------------------------------------------------

FILE: Tests/bootstrap.php
--------------------------------------------------------------------------------
FOUND 0 ERROR(S) AND 1 WARNING(S) AFFECTING 1 LINE(S)
--------------------------------------------------------------------------------
 1 | WARNING | A file should declare new symbols (classes, functions,
   |         | constants, etc.) and cause no other side effects, or it should
   |         | execute logic with side effects, but should not do both. The
   |         | first symbol is defined on line 3 and the first side effect is
   |         | on line 5.
--------------------------------------------------------------------------------


php php-cs-fixer.phar fix .


In an ideal world, every PHP project would adopt the recommendations found in PSR-1 and PSR-2. However, due to taste (i.e. “Naming convention x looks better than y!”, “Tabs over spaces!”) and historical segmentation between various coding styles, there have only been a sparse amount of PHP projects adopting PSR-1 and PSR-2 in its entirety.


net.tutsplus.com/tutorials/php/psr-huh

By everyone shirking their own preferences, we have one consistent style from the outside-in, meaning I can use ANY package – not just whichever happens to be camelCase.


- Phil Sturgeon in the PHP-FIG mailing list

PSR-3: Logger Interface


Describes a common interface for logging libraries.

PSR Log Package


Common interface for logging libraries.

Holds all interfaces/classes/traits related to PSR-3.

Note that this is not a logger of its own. It is merely an interface that describes a logger. See the specification for more details.

A shared interface standard, like PSR-3, results in frameworks, libraries and other applications being able to type hint on that shared interface, allowing developers to choose a preferred implementation.


net.tutsplus.com/tutorials/php/psr-huh

In other words: if a logging component is known to adhere to PSR-3, it can simply be swapped with a different PSR-3 compliant logging component. This assures maximum interoperability between calls to logger implementations.


net.tutsplus.com/tutorials/php/psr-huh

Monolog implements PSR-3


It’s therefore known to implement the Psr\Log\LoggerInterface and its associated guidelines found in the PSR-3 document.


Because of this, you could swap out Monolog for any other PSR-3 compliant logger... if someone else felt like writing one.


github.com/Seldaek/monolog

PSR-4: Autoloader


 This PSR describes a specification for autoloading classes from file paths. It is fully interoperable, and can be used in addition to any other autoloading specification, including PSR-0. This PSR also describes where to place files that will be autoloaded according to the specification.


...and it's now accepted (yay!)

Namespaces are real, no need to fake it


No more Zend_Email_Imap, it's Zend\Email\Imap. PSR-0 lets either of those map to the same filepath, which causes some oddities.


PSR-4 removes this.

Overly Verbose Folder Structure.


In ye-oldén times, Foo/Bar/Baz would link to vendor/Foo/Bar/Baz.

Now that Composer is a thing, its more common to see a mapping like: Foo/Bar/Baz would link to vendor/foo/bar/src/Foo/Bar/Baz.

PSR-4 will let you configure Foo/Bar as a prefix, then your folder structure can map Foo/Bar/Baz to vendor/foo/bar/src/Baz.

Autoloader error handling


Autoloaders shouldn't throw exceptions or raise errors - they should be interoperable, as there may be others registered to pick up misses.

Why?

Pros:

  • Shallower directory structures
  • More flexible file locations 
  • Stops underscore in class name from being honored as directory separator
  • Makes implementations more explicitly interoperable
Cons:

  • It is no longer possible, as under PSR-0, to merely examine a class name to determine where it is in the file system (the "class-to-file" convention inherited from Horde/PEAR).

Composer team on board - already a WIP


Assuming you're using namespaces (and not _'s), upgrading an application will require nothing, it will be completely seamless and use the existing Composer autoloader.


PSR-0 will probably be deprecated some day, but no date has been set for that. If it happens, it will be a damn long time away.

Why are the PSR's so varied?


The PHP-FIG is not a standards body, it's a group that makes recommendations for ways in which frameworks (and other projects in general) can combine their efforts to create interoperable code. That gives it a fairly open-ended remit when it comes to what it releases as PSR's.

- Phil, again,  in the PHP-FIG mailing list

Where next?


HTTP Client and Message PSRs?

Cache

PHPDoc


26 adapter classes!
This to me is the central point of the PHP-FIG as by defining these standards it can stop the need to build 6 different damn adapter classes for your composer package if you want it to work with Buzz, Guzzle, Zend HTTP, Curl, Whatever). This happens a lot and it sucks.

- some Bristolian guy, on his blog

Further reading


The FIG intends to host a cross-section of the PHP ecosystem, not only framework developers.


Thanks!


Questions?








Copy of PHP-FIG PSR WTF

By boxcore

Copy of PHP-FIG PSR WTF

  • 397