PHP Coding Conventions

The following conventions apply to PHP / back-end code.

Basics

The following PSR (PHP Standardisation Request) must be followed:

Besides that we are using Symfony 4.1 in all of our PHP based components and attempt to follow its rules.

General

  • No mixed data type hints or mixed return type hints
  • Tests for all important, critical or complex code, especially in services
  • Session must not contain any data but the logged in users ID
    • Never use Session beyond the controller
  • Always use the Request object to access request data (Header, Body, Query String, Files, …)
    • Only use request objects in controllers
  • Do not suppress any error from PHP during runtime (@)
  • Do not use static (except for factory methods in data objects)
    • NEVER use static class properties

Functions and Methods

  • Keep functions small and modular
  • Function and methods have a limit of 50 LOC

Classes

  • Properties first
  • Try to limit the number of public methods on services to a maximum of 10
  • Helper methods should be below the public method using them
  • Classes should not exceed 256 LOC

Naming

  • Don't use types in names
  • Keep abbreviations to a minimum
  • Always use English naming
    • Try to use variable names relating to a common understanding of the domain
    • A variable name should describe what is contained in the variable
    • Be nice to the reader and your co-worker

Use Exceptions

  • Extend from component (Base Exception)
  • Always throw exception in case of errors, do not return null or false
  • Handle exceptions sensibly at latest in controllers
    • Display sensible error messages depending on exception type
    • Log technical failures, alert operations
  • Try to avoid returning false in case of actual Exceptions
  • Return false is fine only in the case of Validation

Gateways

  • Get-Methods (like getById) are allowed to throw an Exception on not found
  • Find-Methods are not allowed to throw Exceptions, null should be returned
  • By default use DQL. If a query needs optimisation or something is not supported write raw SQL
  • No Business Logic – simple checks or mapping is OK
  • Save/Read data from/to database or any other data source
  • Return and receive always data objects. Primitive types in documented edge-cases
  • Services depend on Gateways (interfaces)

DataObjects

  • Use them for all data -- never StdClass
  • Never use arrays as data structures
  • Data objects must not aggregate "active" dependencies (gateways, services)
  • Only logic modelling eternal truth
  • Avoid to create multiple DataObjects with same name
  • Do not use getter / setters: Use public properties and direct property access

Service

  • Max 4 dependencies
    • Techincal constraints like logging and caching should be moved into Decorators
  • All dependencies are injected
  • The business logic should be contained here
  • No dependencies on externals – each external class should be wrapped behind a facade (Symfony, DB (Gateways), Webservices, …)
    • Not even the Request object, but DataObjects created from the request data
  • Respect Law Of Demeter – only work with direct dependencies

Controller

  • Catch Exceptions
  • Check Permissions
  • Convert incoming data into object
  • No (Business) Logic (only validation or Simple authorization like "is logged in")
  • Use Request and Response objects

MySQL

  • Write keywords in statements in uppercase
  • No JOINs without condition
  • No implicit JOINs
  • All table names and column names are in singular
  • All columns in a table (user) are prefixed with the unique table prefix (u_) -- especially also the id (u_id)
    • A foreign key reference will use the column name from the referenced table (comment:u_id)