├── LICENSE └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 freshp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP - the small things 2 | A summary of small things a php programmer can do to improve the code and the readability of code. 3 | 4 | There are so brilliant programming concepts and paradigms in the PHP community. I don't want to chew them again and again. 5 | But I think everybody needs some easy small things we can improve in our everyday's work. 6 | There are so many books, conferences, videos and so on, where you can learn great new or old architectures. 7 | But most of the time you have to start from scratch or read thick books before you can start. 8 | That is fine, but IMO there are so many small things you can improve and start now. 9 | I saw many developer doing great work in general, but no one understands the goal of their software or the way to the goal. 10 | There will be the day they dont support their fancy tools any more. 11 | And a new developer starts from scratch, because he or she do not understands the code at all. 12 | Everybody can produce legacy code. (legacy code is code that works) So IMO the best code is code that everybody can understand by reading it. 13 | This repository should help to see, that there are so many small things we can improve from now on. 14 | 15 | I am convinced that in a complex situation the small things makes the difference. 16 | 17 | 1. [PHP programming](#php-programming) 18 | 1. [Meta theses](#meta-theses) 19 | 1. [PHP programming theses](#php-programming-theses) 20 | 1. [Learning the basics](#learning-the-basics) 21 | 1. [Blogs](#blogs) 22 | 1. [Tools](#tools) 23 | 1. [Use web services for default tasks](#use-web-services-for-default-tasks) 24 | 1. [Free online tools](#free-online-tools) 25 | 1. [IDE](#ide) 26 | 1. [Important composer packages](#important-composer-packages) 27 | 1. [Code reviews](#code-reviews) 28 | 1. [Code review thesis](#code-review-theses) 29 | 1. [Documentation](#documentation) 30 | 31 | ## PHP programming 32 | 33 | ### Meta theses 34 | Every thesis can be advice. 35 | * Every advice has its own context, and context beats any advice. 36 | * Use common sense for every advice; these are not rules. 37 | * Skip any advice that doesn't bring a benefit. 38 | * Avoid subjective perspectives in advice. 39 | * Advice should have a real, tangible benefit. 40 | * Advice should generally apply broadly. 41 | * You don't have to follow all advice, but you should know they exist. 42 | * Comment: Don't miss any advice without understanding the reason. 43 | 44 | ### PHP programming theses 45 | These are some theses I have developed in almost 20 years of programming in teams. 46 | It is just a numbered list to discuss it. 47 | New theses will be listed at the end of the list, feel free to add some. 48 | The given list is far from complete, but I have raised these points too many times and they may help others too. 49 | My context has always been the development of products that need to be adapted and expanded over a longer period of time. 50 | It was never a question of whether a line of code would be adapted, but when. 51 | Defects in these products lead to direct financial losses or a work blocker for teams. 52 | 53 | 54 | 1. **What cannot be tested should not be programmed.** 55 | - *Comment:* Start with [PHPUnit](https://phpunit.de). 56 | - **Example:** Implementing unit tests for all public methods ensures that each function performs as expected. 57 | 58 | 2. **Use type declarations for all properties, functions (return types and parameters), and variables.** 59 | - *Comment:* They exist for a reason. 60 | - **Reference:** [PHP Type Declarations](https://www.php.net/manual/en/language.types.declarations.php) 61 | 62 | 3. **Immutability is king.** 63 | - *Comment:* Know the [advantages](https://hackernoon.com/immutability). 64 | - **Example:** Using immutable objects can prevent accidental changes to data. 65 | ```php 66 | final class ImmutableUser { 67 | public function __construct(private readonly string $name) { 68 | } 69 | 70 | public function getName(): string { 71 | return $this->name; 72 | } 73 | } 74 | ``` 75 | 76 | 4. **Always check clauses with the most accurate possible value.** 77 | - *Comment:* Return types can change, but the clause should not. 78 | - **Example:** `if (true === $user->isActive())` is preferred over `if ($user->isActive())`. 79 | 80 | 5. **Avoid else statements and use early returns.** 81 | - *Comment:* [Reasons](https://szymonkrajewski.pl/why-should-you-return-early/). 82 | - **Example:** 83 | ```php 84 | function example(bool $value): void { 85 | if (false === $value) { 86 | return; 87 | } 88 | // Rest of the code 89 | } 90 | ``` 91 | 92 | 6. **Do not use arrays across class or function boundaries.** 93 | - *Comment:* They are not typed. 94 | - **Example:** Use value objects or DTOs instead of arrays. 95 | ```php 96 | final class UserDTO { 97 | public function __construct(public readonly string $name, public readonly string $email) { 98 | } 99 | } 100 | 101 | function createUser(UserDTO $userDTO) { 102 | // Use $userDTO 103 | } 104 | ``` 105 | 106 | 7. **String concatenation should always use `sprintf`.** 107 | - *Comment:* It is safer, easier to extend and it prevents magic. It is slower than normal concatenation. 108 | - **Example:** 109 | ```php 110 | $name = "John"; 111 | $greeting = sprintf("Hello, %s!", $name); 112 | ``` 113 | 114 | 8. **Use Yoda conditions.** 115 | - *Comment:* prevents accidental assignment and let your eye quicker find the info. 116 | - **Example:** 117 | ```php 118 | if ( 119 | 'no' === $answer 120 | || 'yes' === $answer 121 | ) { 122 | // Do nothing 123 | } 124 | if (42 === $answer) { 125 | // Do something 126 | } 127 | ``` 128 | - **Reference:** [To Yoda or Not to Yoda](https://knowthecode.io/yoda-conditions-yoda-not-yoda) 129 | 130 | 9. **Use `declare(strict_types=1);` at the top of every PHP script.** 131 | - *Comment:* [Explanation](https://brainbell.com/php/strict-type.html). 132 | - **Example:** Ensures that all type declarations are strictly enforced. 133 | ```php 134 | declare(strict_types=1); 135 | 136 | function add(int $a, int $b): int { 137 | return $a + $b; 138 | } 139 | ``` 140 | - **Reference:** [Strict Types in PHP](https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict) 141 | 142 | 10. **Use `final` for your objects.** 143 | - *Comment:* Inheritance is complex to manage. 144 | - **Example:** 145 | ```php 146 | final class User { 147 | // Class implementation 148 | } 149 | ``` 150 | - **Reference:** [Final Keyword in PHP](https://www.php.net/manual/en/language.oop5.final.php) 151 | 152 | 11. **Default visibility for properties and functions should be `private`.** 153 | - *Comment:* Treat public functions/properties as public APIs. 154 | - **Example:** 155 | ```php 156 | final class User { 157 | public function __construct(private string $name) {} 158 | 159 | public function getName(): string { 160 | return $this->name; 161 | } 162 | } 163 | ``` 164 | - **Reference:** [Visibility in PHP](https://www.php.net/manual/en/language.oop5.visibility.php) 165 | 166 | 12. **Use annotations sparingly and only when necessary.** 167 | - *Comment:* Prefer PHP8 attributes, return types and property types. 168 | - **Example:** 169 | ```php 170 | #[PHPUnit\Framework\Attributes\DataProvider('provideNotAllowedKeys')] 171 | public function testShowErrorWithNotAllowedKeys(string $key) 172 | ``` 173 | - **Reference:** [PHP8 Attributes](https://stitcher.io/blog/php-8-attributes) 174 | 175 | 13. **Do not use full namespaces in the code; use `use` statements.** 176 | - *Comment:* Highlights external dependencies. 177 | - **Example:** 178 | ```php 179 | use Vendor\Package\Class; 180 | 181 | $object = new Class(); 182 | ``` 183 | - **Reference:** [Namespaces in PHP](https://www.php.net/manual/en/language.namespaces.importing.php) 184 | 185 | 14. **Traits should never use traits.** 186 | - *Comment:* Avoid complex inheritance. 187 | - **Example:** Avoid nested traits to reduce complexity. 188 | - **Reference:** [Traits in PHP](https://www.php.net/manual/en/language.oop5.traits.php) 189 | 190 | 15. **Strings should be constants.** 191 | - *Comment:* Reduces errors and increases reusability. 192 | - **Example:** 193 | ```php 194 | public const string STATUS_ACTIVE = 'active'; 195 | ``` 196 | - **Reference:** [Constants in PHP](https://www.php.net/manual/en/language.constants.php) 197 | 198 | 16. **Do not check in commented or unused code.** 199 | - *Comment:* Use version control. 200 | - **Example:** Clean up code before committing. 201 | - **Reference:** [Best Practices for Version Control](https://www.atlassian.com/git/tutorials/comparing-workflows) 202 | 203 | 17. **Avoid abbreviations in the code.** 204 | - *Comment:* Leverage IDE features. 205 | - **Example:** Use `description` instead of `desc`. 206 | - **Reference:** [Clean Code Practices](https://www.oreilly.com/library/view/clean-code/9780136083238/) 207 | 208 | 18. **Use PHAR files for dev-dependency tools.** 209 | - *Comment:* Reduces conflicts and speeds up requirements. 210 | - **Example:** Use `phpunit.phar` for PHPUnit. 211 | - **Reference:** [PHP Archive (PHAR)](https://www.php.net/manual/en/intro.phar.php) 212 | 213 | 19. **Do not use asynchronous techniques in a synchronous language.** 214 | - *Comment:* Different paradigms can lead to complexity. 215 | - **Example:** Avoid mixing async JS techniques in PHP. 216 | 217 | ## Learning the basics 218 | This is just a small snapshot I can recommend. 219 | (If you buy books please think about second hand books. The given links are more for information. 220 | Think twice before you order it.) 221 | 222 | * Principles of object oriented design ([web](http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod)) 223 | * The clean coder ([book](https://www.amazon.de/Clean-Coder-Conduct-Professional-Programmers/dp/0137081073) | [web](https://clean-code-developer.de/)) 224 | * Extremely defensive PHP ([video](https://www.youtube.com/watch?v=8d2AtAGJPno) | [slides](https://ocramius.github.io/extremely-defensive-php/)) 225 | * Design pattern ([web](https://designpatternsphp.readthedocs.io/en/latest/README.html)) 226 | * PHP standards recommendations [PSR](https://www.php-fig.org/psr/) 227 | * Semantic versioning ([web](https://semver.org/)) 228 | * Refactoring ([book](https://www.amazon.de/Refactoring-Improving-Design-Existing-Technology/dp/0201485672)) 229 | * Principles of package design ([book](https://www.amazon.de/Principles-Package-Design-Creating-Components/dp/1484241185)) 230 | * A philosophy of software design ([book](https://www.amazon.de/Philosophy-Software-Design-John-Ousterhout/dp/1732102201)) 231 | * Pro git ([ebook](https://git-scm.com/book/de/v2)) 232 | * The mythical man-month ([book](https://www.amazon.de/-/en/Frederick-Brooks/dp/0201835959)) 233 | 234 | ## Blogs 235 | There are many more interesting blogs, but these selection cross up my way multiple times. 236 | It could be beneficial to look also through old articles. 237 | 238 | * https://blog.jetbrains.com/phpstorm/ 239 | * https://blog.cleancoder.com/ 240 | * https://matthiasnoback.nl/ 241 | * https://ocramius.github.io/ 242 | * https://www.sitepoint.com/php/ 243 | * https://www.zend.com/blog 244 | * https://localheinz.com/articles/ 245 | * https://stitcher.io/ 246 | 247 | ## Tools 248 | * use package managers for your local requirements 249 | * for example in MacOS install [brew](https://brew.sh/index_de) 250 | * install [php over brew](https://formulae.brew.sh/formula/php) on MacOS 251 | * *comment:* the big advantage is to have multiple versions linked by brew directly from the cellar 252 | * install [git over brew](https://gist.github.com/derhuerst/1b15ff4652a867391f03) on MacOS 253 | * install [Oh My Zsh](https://github.com/ohmyzsh/ohmyzsh) bash on MacOS 254 | * install [composer](https://getcomposer.org/download/) globally for dependency management in PHP 255 | * install [xdebug](https://xdebug.org/docs/install) for debugging, tracing, profiling and the codecoverage 256 | 257 | ### Use web services for default tasks 258 | * use a automation server like [jenkins](https://jenkins.io/) for continuous integration, continuous deployment or any other automation 259 | * use a remote repository server like [gitlab](https://about.gitlab.com/) or [bitbucket](https://bitbucket.org/) or at least github 260 | * use a private package repository like [satis](https://github.com/composer/satis) 261 | * use a error tracker like [sentry](https://sentry.io) 262 | 263 | ### Free online tools 264 | * if you need regex, than use [this page](https://regex101.com/) 265 | * you want to schedule a cronjob, than look at [this page](https://crontab.guru/) 266 | * you are not sure with your version constraint, than look at [this page](https://jubianchi.github.io/semver-check/#/) 267 | * communication is the key, use [showcode](https://showcode.app/) for better presentations 268 | 269 | ## IDE 270 | * use an IDE for example [PHPStorm](https://www.jetbrains.com/phpstorm/) 271 | * set PHPStorm up ([jetbrains documentation](https://www.jetbrains.com/help/phpstorm/configuring-php-development-environment.html)) correctly 272 | * use [inspections](https://www.jetbrains.com/help/phpstorm/code-inspection.html) 273 | * use one of the default codestyles in PHPStorm for example [PSR-12](https://www.php-fig.org/psr/psr-12/) 274 | * use [xdebug](https://xdebug.org/) in PHPStorm ([documentation](https://www.jetbrains.com/help/phpstorm/configuring-xdebug.html)) 275 | * take a look at PHPStorm features like ai testing, testing, database, deployment, version control, ... [tutorials](https://blog.jetbrains.com/phpstorm/category/tutorials/) 276 | * use plugins of PHPStorm: 277 | * [github-copilot](https://plugins.jetbrains.com/plugin/17718-github-copilot) 278 | * [.env](https://plugins.jetbrains.com/plugin/9525--env-files-support) 279 | * [php annotations](https://plugins.jetbrains.com/plugin/7320-php-annotations) 280 | * select a plugin for framework support like [symfony](https://plugins.jetbrains.com/plugin/7219-symfony-support) 281 | 282 | ## Important composer packages 283 | The list of packages is not complete, but you can start projects from this stack. 284 | 285 | * Composer package to handle [Security advisories](https://github.com/Roave/SecurityAdvisories). 286 | * Do not commit secrets and use [.env's](https://github.com/vlucas/phpdotenv) instead. 287 | * The testing framework [PHPUnit](https://github.com/sebastianbergmann/phpunit). 288 | * If you reached nearly 100% of code coverage than you can go further with [infection](https://github.com/infection/infection). 289 | * Static code analyses with [PHPStan](https://github.com/phpstan/phpstan) or [Psalm](https://github.com/vimeo/psalm). 290 | * PHP Codesniffer with [PHPCS and PHPCBF](https://github.com/PHPCSStandards/PHP_CodeSniffer). 291 | * Dependency injection container [PHP-DI](https://github.com/PHP-DI/PHP-DI) 292 | * PHP library to generate [UUIDs](https://github.com/ramsey/uuid) or use [ULIDs](https://github.com/robinvdvleuten/php-ulid). 293 | * Simple composer PHAR file handling with [tooly](https://github.com/tommy-muehle/tooly-composer-script). 294 | 295 | ## Code reviews 296 | Start making code reviews. If you dont know how? Read this [article](https://medium.com/palantir/code-review-best-practices-19e02780015f) 297 | 298 | ### Code review theses 299 | > You are not your Code! 300 | * code reviewer do not comment on you, they comment your code 301 | > If you find code you do not understand, ask. 302 | * It is not the question if you should know, but when. 303 | 304 | ## Documentation 305 | I only saw one approach, which seems to be suitable for software projects and this is [arc42](https://arc42.org/). 306 | 307 | For further diagrams or graphs you can use [draw.io](https://app.diagrams.net/). 308 | 309 | ## Estimation 310 | "Definition of 'estimate' according to Duden: (without exact measurement, based only on experience) to determine approximately" → We do not expect these to be exact and always correct, but they should get better. 311 | 312 | You have to learn how to approach it. Estimate before you start the task, then track the time and compare at the end what influenced you. 313 | 314 | Maybe start by using PERT result = (best case estimation + 4 * normal estimation + worst case estimation) / 6 315 | 316 | ## Uncategorized shortlist: 317 | 318 | * Use composer 319 | * Use [composer scripts](https://getcomposer.org/doc/articles/scripts.md) for automation 320 | * I have good experience with providing a static code analysis and tests with composer scripts in combination with bash scripts 321 | * Use [githooks](https://git-scm.com/docs/githooks) like [here](https://gist.github.com/freshp/977f4b5bc67bd2426450680adb172d54) to prevent commit cascade with fix tests, static code analysis, and code style 322 | * Use [openapi](https://www.openapis.org/) for API documentation 323 | * Adopt [dependency injection](https://www.php.net/manual/en/language.oop5.decon.php) 324 | * Use [value objects](https://wendelladriel.com/blog/understanding-value-objects-in-php) for domain logic 325 | * Do not use external class directly, use a wrapper 326 | * Use database migrations for example with [phinx](https://phinx.org/) 327 | * Use a logger like [monolog](https://github.com/Seldaek/monolog) 328 | * Use timestamp as exception code 329 | * use the current timestamp as exception code while creating the exception 330 | * it is better testable and the error log directly leads to the code 331 | * Use [design patterns](https://refactoring.guru/design-patterns/php) if you have their usecases 332 | * Use a factory for object creation 333 | * Use a repository for database access 334 | * You can mock them in tests 335 | * You know where to find the database access 336 | * Use [`filter_input`](https://www.php.net/manual/de/function.filter-input.php) to validate user input 337 | * Do not reinvent the wheel 338 | * Each repository should have a readme and the readme should be updated regularly 339 | * Use final interfaces to collect typed constants 340 | * So you can bundle up contents like API date formats or other stuff. 341 | * Know the packages of [php-fig](https://github.com/php-fig) 342 | * Look through the packages of [phpleague](https://github.com/thephpleague) 343 | * If you deal with money look at [moneyphp](https://github.com/moneyphp/money) 344 | * Use [flysystem](https://github.com/thephpleague/flysystem) or [vfsStream](https://github.com/bovigo/vfsStream) to test file handling 345 | * Use [symfony intl](https://packagist.org/packages/symfony/intl) for internationalization 346 | * Use [symfony console](https://packagist.org/packages/symfony/console) for console applications 347 | * Most reason why I could not write tests is because I could not mock core functions but you can [example-test-php-core-methods](https://github.com/freshp/example-test-php-core-methods) 348 | * Working in teams is about working with API contracts. The smallest API contract are the public methods in a class. 349 | --------------------------------------------------------------------------------