Download the PHP package shrikeh/php-coding-bible without Composer
On this page you can find all versions of the php package shrikeh/php-coding-bible. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download shrikeh/php-coding-bible
More information about shrikeh/php-coding-bible
Files in shrikeh/php-coding-bible
Package php-coding-bible
Short Description PHP Coding bible and associated sniffs
License MIT
Informations about the package php-coding-bible
PHP Coding Bible
Bible of how we want to write maintainable code and applications.
Ethos
While the Zen of Python is, well, about Python, our code can also benefit from the wisdom of Tim Peters:
- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Flat is better than nested.
- Sparse is better than dense.
- Readability counts.
- Special cases aren't special enough to break the rules.
- Although practicality beats purity.
- Errors should never pass silently.
- Unless explicitly silenced.
- In the face of ambiguity, refuse the temptation to guess.
- There should be one-- and preferably only one --obvious way to do it.
- Although that way may not be obvious at first unless you're Dutch.
- Now is better than never.
- Although never is often better than right now.
- If the implementation is hard to explain, it's a bad idea.
- If the implementation is easy to explain, it may be a good idea.
- Namespaces are one honking great idea -- let's do more of those!
Overarching Concepts
Don't. Ship. Shit.
"You don't guess that your code works; You know that it works"
- Uncle Bob
Here's the talk. Required viewing.
Code without tests is not production-ready: it's as simple as that. Your tests should mean you know it works before it's deployed. That may mean refactoring code, but we are professionals and the job isn't supposed to be easy.
The Low-Level stuff
Write your code to be:
Tests are first-class citizens in your application
Think about it. They're the reason you don't have to write so much documentation, how you know you aren't breaking somebody else's code (and that they can't break yours). They need to be fast and light, atomic enough they can run in parallel, and be easily maintained. So yes, they are equally as valuable as the application code in knowing you're done. Treat them with the same care you would for application code (which is why they should get linted and quality checked as well).
Classes that are easy to test are easy to use and maintain
A core advantage of TDD isn't about tests but how writing code to pass tests makes you keen to easily setup the Subject Under Test, and that the SUT has a limited number of methods and permutations that require testing.
Favour Composition over Inheritance
There should be a very good reason to extend a class. Inheritance causes all sorts of problems with tests, overriding methods, etc. Make your classes final
and use collaborators.
Classes Should Self-Validate On Construction
It should be impossible for an object to be created in an invalid state. Objects should self-validate upon construction to ensure they are meaningful and to capture early problems.
A constructor shouldn't have to normalize data, just validate it
In the case where an object could be created from multiple types of data, it's better to make the __construct()
method private and instead use Static Named Constructors. The static methods can then normalize the data, while the true constructor validates it:
The "Rule" Of Three
A method, including a constructor, should have a maximum of three arguments to it.
Collaboration is Key
Collaborators, be they aggregates or providers of functionality, provide the building blocks of good code. They allow the above "rule" to be more easily followed, aid in testing, maintainability, and reuse.
A simple Aggregate example for use within a Customer
:
Because the above class is using Value Objects, which self-validate themselves, the aggregate needs no validation itself. This then could be used as an argument to a Customer
constructor.
But how should you access these aggregated details? Well...
Practice the Law of Demeter
"When one wants a dog to walk, one does not command the dog's legs to walk directly; instead one commands the dog which then commands its own legs."
- Wikipedia
The Law of Demeter is a principle of least knowledge; that is, the properties and structure of an object should not be replied upon by something using it. Instead, the object should have a method that does the work for the external user:
Failure should be exceptional
Classes should do what is expected of them or throw a specific Exception. Don't return true
; it is expected to work!
Remember: if you are relying on a collaborator, and it throws an Exception to use the previous Exception:
Concerned the above doesn't return an ID? Why do you need one, your application has already specified the UID ahead of time via the use of UUIDv5 or UUIDv6.
Comments are a code smell
Think about it: why is your code so complex you need to explain it? Strong variable names and typing, combined with equally strong method names and brevity, should not require War & Peace to describe them. Functional testing with Gherkin, combined with unit testing obeying the principle of Specification By Example, should provide enough information.
Set is Evil
Objects should be immutable, and created in a specific state which they carry for their lifetime.
If you must use set
, it should return a new instance with the new value and leave the original unchanged:
Get is Evil
Or at least, getters are not necessary for simply returning property values from PHP 8.1, following the addition of public readonly
properties:
replaces
Why?
There are two main reasons to follow the public readonly
approach:
- Brevity - The first code snippet above is much shorter than the second. It's fewer lines of code to write, and more readable too.
- Saves on unit testing - In a project with a minimum code coverage expectation, it would be necessary to unit test all methods including getters. Whilst this is a trivial test to write, no test is required with the
public readonly
approach.
Better still, make the entire class readonly wherever possible:
New is Evil
There are only a few things that should create other things:
- An object should be able to create a new instance of itself (ie to follow the practice of immutability above)
- A dedicated factory, ideally meeting an interface.
- Dependency Injection containers
Let's imagine a database repository matching the following contract:
Now, an implementation that essentially handles the query and Exception handling, without having to know how to create the CustomerDetails
:
The above is going to be far easier to mock, test, and maintain.
Make variables and methods private by default
You should only make the minimum number of methods public to fulfill the contract of external use.
Prefer class constants over magic numbers
You know how it is. Months after you wrote a wonderful algorithm that is blisteringly fast and your peers adore you for, you now have to go back into it with a new team member.
Why is it 2.17, they ask innocently? You panic, not remembering what this magic number is. You see the future all too clearly now: how they will see through your facade of professionalism, how your team will mock you, your family turn their backs on you, and LinkedIn will close your profile. As the sweat pours down your forehead, desperately trying to remember what any of the calculation means, you can tell it is already too late as the first drizzle of perspiration crashes against the keys of your keyboard, and you smell the burning of electronics.
If only you had written it like this:
Prefer Enums over multiple class constants of the same "thing"
Having replaced both your predecessor and their moisture-damaged keyboard, you resolve to not make the same mistakes.
Here's a (real) extract from a class written before PHP had enums:
You keep your cool, and you refactor the class by extracting these constants into an Enumerable:
Enforce strict typing with declare(strict_types=1)
Newer versions of PHP allows scalar
types declarations.
Unfortunately these types can still be coerced into wrong types, take as an example:
See [https://3v4l.org/6YfXoK]()
This will simply output 123
Now we add declare(strict_types=1);
See [https://3v4l.org/smJf1]()
And we now get:
in php >= 8 and for php 7 we get:
So practice safe coding and always use declare(strict_types=1);
All versions of php-coding-bible with dependencies
shrikeh/testing-metapackage Version >=0.3
slevomat/coding-standard Version ^8.4
squizlabs/php_codesniffer Version ^3.7