Skip to content

Instantly share code, notes, and snippets.

@Potherca
Last active December 14, 2023 16:36
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Potherca/9afb08c7cf1beab383564902bbe67be3 to your computer and use it in GitHub Desktop.
Save Potherca/9afb08c7cf1beab383564902bbe67be3 to your computer and use it in GitHub Desktop.
Rules for creating more robust code in PHP.
⚠️ This document is still under heavy development ⚠️
  • Avoid Generally speaking it is best not to use a certain thing, but there are exceptions to the rule and it is not uncommon to encounter these in code.
  • No not use Do not use. Ever. No exceptions, no excuses.

There are no "rules" other than the "rules" you set for yourself.

Discuss the game with the other players!

Simple (and specific) rules

The following rules are specific enough that they can be validated from a checklist. (A PHP_CS sniff could even be created for these). They refer to specific occurances in code.

  1. Use array_walk instead of foreach
  2. Use the type safe comparison operators. === in stead of ==
  3. Methods should be always final, private or abstract
  4. Only one action per line
  5. Use "maps" instead of switch's
  6. Use explicit checks if ($valid === true) rather than if ($valid) and if ($valid === false) rather than if (! $valid)
  7. Don't hard-code numbers or strings
  8. Use (the result of) function calls in if statements Rather than if ($email !== '' && strpos($email, '@') !== false && strpos($email, '@') !== 0 /* && etc.*/) { /*...*/} use $valid = $this->isValidEmailAddress($email); if ($valid === true) { /*...*/}
  9. Always review your own work
  10. Don't use boolean parameters (make 2 separate functions instead)
  11. Have a single-line doc-block above class properties and getters/setters (as these should be simple, boring and stupid)
  12. only return once per function "Return early, return often" is a cop-out to hide complexity (the code path is still there, it is just hidden). "But now I have to read!" --> Place the if body in a separate method FFS!
  13. Only extend abstract classes
  14. Place error message in class constants and use sprintf or vsprintf
  15. As static === global, do not create static class methods
  16. Do not use global or global variables like $_GET, $_POST, etc. (inject these into class/functions)
  17. Don't make final classes. Make final functions. If any function becomes un-final, all other functions need to be changed. That is one ugly diff.
  18. Use $variable = $this->getVariable() at the start of a method and access $variable for the rest of the function. Easier to read, refactor and understand. (Part of the retrieve data, do logic, return result paradigm),
  19. Prefer methods over indenting
  20. Avoid using empty for comparisons
  21. Do not use Left-hand comparisons (yoda comparisons) in control structures reasoning The main reason usualy quoted for using left-hand comparisons in control structures is that it makes it harder to break the code. Sadly it also makes the code "wrong" to read. While the right-hand comparison if($nA == 1) could accidentally become if($nA = 1), it is a lot less likely to happen if you adhere to using type safe comparison operators. if($nA === 1) becoming if($nA == 1) is a lot less harmfull, no?
  22. Values should be checked at entry point. As a general rule of thumb we never trust the type of anything that does not belong to the closed scoped of the current class, method or function.
  23. Exceptions should be of a specific flavour, without going into exact detail. Detail is what the exception message is for. Always add a (little) message to the exception. The error message should always be user friendly so that the exceptions can be used to inform the user of any mishaps.
  24. Avoid Continue and Break Continue and break are really just gotos in disguise and like goto they should be used sparingly as they are magic in code. With a simple spell the reader is beamed to God knows where.
  25. Avoid the Ternary Operator
  26. Use task tags (@TODO:, @FIXME:, @CHECKME:, and @KLUDGE:) to draw attention to potentially problematic parts of code.
  27. Don't use slash "/" as delimiter when matching URLS or paths

More advanced (and more generic) rules

The following rules are more generic. They cannot be checked off from a list, they require mental effort when implementing and reviewing. They still mostly apply to specific instances in the code.

  1. Use Immutable/Data/Container objects
  2. Separate Decision, Data and Logic
  3. Do one thing: input/output or side-effect
  4. Prefer methods over comments
  5. Use the "set defaults -> run logic -> return result" pattern
  6. Split long functions up -> What is long? When is "long" actually "too long"
  7. Write code from a readers perspective
  8. Think ahead Look at changes in the code from the perspective of future diffs and commits/changesets
  9. Use composite classes, not extends (i.e. proxies, facades, wrappers and decorators). This rule compliments the "only extend abstract" rule. If you should not extend a class, then what should be done? Add the class as a property to another class!
  10. In case of doubt, discuss it with another developer. reasoning Don't waiste your time mulling over a question, just ask someone else to help you solve your conundrum. Saves both time and yourself from banging your head against the wall.
  11. Make sure your code has been reviewed by another developer. reasoning Peer review is one of the best tools we have available to us for catching potential bugs and inconsistancies in the code or documentation thereof. Use it!

Pro (and pattern-like) rules

The following rule are way more generic. They are more top-level paradigms. They cannot be implemented in one specific location in the code but require a broader and more continuous effort. This is where coding reaches craftmanship.

  1. Pick a paradigm. Try it out for 3 months. Document it and keep it or avoid it.
  2. Keep vendor code to an absolute minimum. Use at least one class to connect to vendor class(es)
  3. Stick to a (documented) naming convention (getfor clean getters, fetch for external retrieval, etc.)
  4. Good code is very boring You can understand everything that happens and there are no surprises... If anything jumps out at you in the code, try to make it more boring (simple, understandable, readable).

Maybe add a word on

  1. Line length For the sake of readability
  2. Using abstractions rather than direct I/O calls
  3. **Read some of these books: ... ** [Clean Code], [Pragmatic Programmer], [Code Complete], [The mythical Man Month], [Peopleware], [The Clean Coder], [Working Effectively with Legacy Code] (https://www.goodreads.com/shelf/show/software-engineering)
  4. Using linters. Always go green! Green? Supergreen!
  5. Readable, Re-useable, Maintainable, Testable
  6. Wrap all primitives and Strings in classes

Naming conventions

  1. Use one word per concept
  2. Use solution/problem/busniess domain based (or oriented) names

People reading your code will be other programmers so they understand solution domain terminology, so make the most of it. - For example, jobQueue is better than jobs

  1. Use verbs for function names and nouns for classes and attributes
  • Be explicit
  • Do not hide code complexity

  • Good code is boring
  • Good code clearly states intent (not just the "what" but also the "why")
  • Good code is easy to read
  • Good code is easy to understand
ℹ️ This document is part of Potherca's Rules for creating more robust code in PHP

Summary of "what"

What is it (Description / Usage scenario / Occurrence)

How does it work (Workings)

Why to avoid / Why this is bad (Rational)

What to do instead (Alternatives)

Counter arguments (and response)

How it might look (Code examples)

Where more information can be found (Resources)

Relevant rules

@rkyoku
Copy link

rkyoku commented Jun 18, 2022

Loved the reference to the 5th Element ^^

I'll keep the array_walk idea, which is quite nice actually! Thanks mate!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment