Magento 2 Coding Standard Best Practices
Magento 2 is a leading e-Commerce Platform. Every retail business from small to large scale wanted to use such a leading platform. Magento Framework provides a number of stores, can manage various payment methods, shipping methods, and enhances performance using third-party extensions.
While using a third-party extension, there are pre-defined coding standards which needs to be followed by the developers. Magento 2 coding standard is used to improve code quality and maintaining interoperability with Magento source code.
Sometimes developers work under short deadlines, and they are not able to maintain coding standards. Quality of code surely affects the performance of code. There are several tools available that automatically checks the Coding Standard of custom modules.
Magento also provides Magento Coding Standard tool which tests Magento code and also includes standards of PHP code Sniffer, PHP Mess-Detector, GrumPHP, PHP Code Beautifier and fixer, and PSR.
What is PHP Code Sniffer (phpcs)?
- PHP Code Sniffer tool is sniffing PHP code, JavaScript code and CSS code.
- Developer can check coding standard in command prompt with the below command:
vendor/bin/phpcs –standard=PSR1, Magento2 –severity=10 [path to Magento module] |
- Developers can also check other Standards like PSR2, PSR12, PEAR, Squiz, Zend, Magento2Framework, and PHPCompatibility.
- PSR (PHP Standard Recommendation) Standards helps to Standardize PHP code. Like PSR1 checks Basic Coding Standards, PSR2 checks Coding Style.
- As shown above, those errors and warnings violates PHP Code Sniffer Standards.
- PHP Code Beautifier and Fixer (phpcbf) tool can fix violations (e.g, blank spaces or blank lines and beautify code.)
vendor/bin/phpcbf –standard=Squiz [path to Magento module] |
What is PHP Mess-Detector (phpmd)?
PHP Mess-Detector also known as phpmd which checks the complexity of code, checks how variables are used in code, and phpmd can detect some unused code.
Magento also provides phpmd tool. By using phpmd, developers can check coding standards of code.
For that, you have to run below command.
vendor/bin/phpmd [path to Magento module] format ruleset |
In the above command,
format argument is used to display instructions or warnings in below formats ansi, baseline, checkstyle, github, html, json, sarif, text, xml
For the ruleset argument, these default formats are available: cleancode, codesize, controversial, design, naming, unusedcode.
- unusedcode ruleset will detect unused code in your module.
- naming ruleset will detect variables and methods whose names are not matching standards.
- codesize ruleset will detect Cyclomatic Complexity, NPath complexity in code.
What is GrumPHP tool?
GrumPHP checks Coding Standards while developers doing git commits. In GrumPHP 5 to 6 Coding Standards will be checked. Sometimes manually checking those standards will be a very tedious process. When GrumPHP installed in your environment, developer will not be able to commit code unless all coding standards will be fulfilled.
To setup GrumPHP use below commands.
composer require –dev phpro/grumphp |
Run above command in root directory of your project.
To setup GrumPHP globally run below command.
composer global require –dev phpro/grumphp |
If you are facing laminas-dependency-plugin version issue, then run below commands.
sudo composer require laminas/laminas-dependency-plugin:2.2.0 sudo composer require –dev phpro/grumphp:* -W |
To setup dependencies of GrumPHP follow below steps.
1. PHPCS
composer global require –dev “squizlabs/php_codesniffer=*” (globally recommended) composer require –dev “squizlabs/php_codesniffer=*” (at project level, need to add project-root/vendor/bin to PATH for direct cli use) |
2. PHPCSFixer2
composer global require –dev friendsofphp/php-cs-fixer (globally recommended) composer require –dev friendsofphp/php-cs-fixer (at project level, need to add project-root/vendor/bin to PATH for direct cli use) |
3. PHPStan
composer global require –dev phpstan/phpstan (globally recommended) composer require –dev phpstan/phpstan (at project level, need to add project-root/vendor/bin to PATH for direct cli use) |
4. PHPMD
composer global require –dev phpmd/phpmd (globally recommended) composer require –dev phpmd/phpmd (at project level, need to add project-root/vendor/bin to PATH for direct cli use) |
5. PHPLint
composer global require –dev php-parallel-lint/php-parallel-lint (globally recommended) composer require –dev php-parallel-lint/php-parallel-lint (at project level, need to add project-root/vendor/bin to PATH for direct cli use) |
GrumPHP will sniff your commits by initializing it in the repository. GrumPHP can be setup in two ways Root level and Module level.
php vendor/bin/grumphp git:init |
Run the above command to init grumphp
- To setup Root level create grumphp.yml (as shown below) file in root directory.
- To setup at Module level create grumphp.yml (as shown below) file in magento-2-root/app/code/MyVendor/MyModule directory.
After that you have to add bin path to your composer.json file.
{ “config”: { “bin-dir”: “../../../../vendor/bin” } } |
Create grumphp.yml file and put below code in that file for Root Level Setup.
grumphp: hide_circumvention_tip: true process_timeout: 120 stop_on_failure: false ignore_unstaged_changes: false tasks: jsonlint: detect_key_conflicts: true metadata: priority: 100 xmllint: ignore_patterns: – “#test/(.*).xml#” metadata: priority: 100 phplint: triggered_by: [‘php’, ‘phtml’] metadata: priority: 200 yamllint: ignore_patterns: – “#test/(.*).yml#” – “#charts/.*#” metadata: priority: 100 composer: file: ./composer.json no_check_all: true no_check_lock: false no_check_publish: false with_dependencies: false strict: false metadata: priority: 80 # validate git commit message git_commit_message: allow_empty_message: false enforce_capitalized_subject: false enforce_no_subject_punctuations: false enforce_no_subject_trailing_period: true enforce_single_lined_subject: true type_scope_conventions: [] max_body_width: 80 max_subject_width: 80 matchers: “Commit message must contain issue topic and number”: /^\[(HOTFIX|BUGFIX|FEATURE|INF RA|MERGE|RELEASE)]\sICRSICRP-\d+\s::\s.*\s\[(COMPLETED|WIP)]/ case_insensitive: true multiline: false additional_modifiers: ” # validate git branch names git_branch_name: whitelist: # allowed branch names: ‘feature-1’, ‘feature-new’, ‘feature-new1’, ‘task-1’, etc – “/(hotfix|bugfix|feature|release|task)-([a-z|0-9]+)$/” blacklist: – “development” – “production” – “staging” – “master” – “infra” allow_detached_head: true # catch not allowed keywords git_blacklist: keywords: – “\\.dev” – “\\.local” – “\\.test” – “<<<<<<<“ – “=======” – “DebuggerUtility” – “ObjectManager::getInstance” – “_GET\\[“ – “_POST\\[“ – “_REQUEST\\[“ – “console.log(“ – “die(“ – “die;” – “exit(“ – “exit;” – “fileadmin” – “localhost” – “phpinfo” – “phpinfo(“ – “print_r(“ – “var_dump(“ – “_objectManager” – “ObjectManagerInterface” triggered_by: [‘php’, ‘js’, ‘html’, ‘phtml’] metadata: priority: 90 # https://devdocs.magento.com/guides/v2.4/coding-standards/code-standard-php.html phpcs: standard: Magento2 tab_width: 4 severity: 10 # can remove this to dis allow all level of severity. error_severity: 10 warning_severity: ~ report: full triggered_by: [phtml, php] metadata: priority: 70 phpcsfixer2: allow_risky: false config: ‘.php_cs.dist’ triggered_by: [‘php’, ‘phtml’] using_cache: true cache_file: ‘./.php_cs.cache’ config_contains_finder: true verbose: true phpmd: ruleset: [‘./dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml’] triggered_by: [‘php’] exclude: – “./app/code/Magento/” – “./app/code/*/*/Setup/” metadata: priority: 70 # uncomment to skip modules using whitelist patterns # whitelist_patterns: # – /^app\/code\/MyVendor\/MyModuleToSkip\/(.*)/ # https://devdocs.magento.com/guides/v2.4/test/testing.html#phpstan phpstan: autoload_file: ~ configuration: ‘./dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/ phpstan.neon’ level: 8 triggered_by: [‘php’] force_patterns: [] ignore_patterns: [] memory_limit: “-1” metadata: priority: 90 phpversion: Project: ‘8.1.*’ |
Create grumphp.yml file and put below code in that file for Module Level Setup.
grumphp: hide_circumvention_tip: true process_timeout: 120 stop_on_failure: false ignore_unstaged_changes: false tasks: jsonlint: detect_key_conflicts: true metadata: priority: 100 xmllint: ignore_patterns: – “#test/(.*).xml#” metadata: priority: 100 phplint: triggered_by: [‘php’, ‘phtml’] metadata: priority: 200 yamllint: ignore_patterns: – “#test/(.*).yml#” – “#charts/.*#” metadata: priority: 100 composer: file: ./composer.json no_check_all: true no_check_lock: false no_check_publish: false with_dependencies: false strict: false metadata: priority: 80 # validate git commit message git_commit_message: allow_empty_message: false enforce_capitalized_subject: false enforce_no_subject_punctuations: false enforce_no_subject_trailing_period: true enforce_single_lined_subject: true type_scope_conventions: [] max_body_width: 80 max_subject_width: 80 matchers: “Commit message must contain issue topic and number”: /^\[(HOTFIX|BUGFIX|FEATURE|INFRA|MERGE|RELEASE)]\sICRSICRP-\d+\s::\s.*\s\[(COMPLETED|WIP)]/ case_insensitive: true multiline: false additional_modifiers: ” # validate git branch names git_branch_name: whitelist: # allowed branch names: ‘feature-1’, ‘feature-new’, ‘feature-new1’, ‘task-1’, etc – “/(hotfix|bugfix|feature|release|task)-([a-z|0-9]+)$/” blacklist: – “development” – “production” – “staging” – “master” – “infra” allow_detached_head: true # catch not allowed keywords git_blacklist: keywords: – “\\.dev” – “\\.local” – “\\.test” – “<<<<<<<“ – “=======” – “DebuggerUtility” – “ObjectManager::getInstance” – “_GET\\[“ – “_POST\\[“ – “_REQUEST\\[“ – “console.log(“ – “die(“ – “die;” – “exit(“ – “exit;” – “fileadmin” – “localhost” – “phpinfo” – “phpinfo(“ – “print_r(“ – “var_dump(“ – “_objectManager” – “ObjectManagerInterface” triggered_by: [‘php’, ‘js’, ‘html’, ‘phtml’] metadata: priority: 90 # https://devdocs.magento.com/guides/v2.4/coding-standards/code-standard-php.html phpcs: standard: Magento2 tab_width: 4 severity: 10 # can remove this to dis allow all level of severity. error_severity: 10 warning_severity: ~ report: full triggered_by: [phtml, php] metadata: priority: 70 phpcsfixer2: allow_risky: false Config: ‘../../../../.php_cs.dist’ triggered_by: [‘php’, ‘phtml’] using_cache: true cache_file: ‘./.php_cs.cache’ config_contains_finder: false verbose: true phpmd: Ruleset: [‘../../../../dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ ruleset.xml’] triggered_by: [‘php’] exclude: – “./app/code/Magento/” – “./app/code/*/*/Setup/” metadata: priority: 70 # uncomment to skip modules using whitelist patterns # whitelist_patterns: # – /^app\/code\/MyVendor\/MyModuleToSkip\/(.*)/ # https://devdocs.magento.com/guides/v2.4/test/testing.html#phpstan phpstan: autoload_file: ~ Configuration: ‘../../../../dev/tests/static/testsuite/Magento/Test/Php/ _files/phpstan/phpstan.neon’ level: 8 triggered_by: [‘php’] force_patterns: [] ignore_patterns: [] memory_limit: “-1” metadata: priority: 90 phpversion: Project: ‘8.1.*’ |
Key points developers need to take care of for coding purposes
Writing Clean Code by Reducing Code Redundancy
It is found that many developers write the same code for the same functionality many times. This, in reality, increases code redundancy, and eventually, the code size gets larger due to the use of many redundant codes. One can write a function or class containing the redundant code and use it when it is required, this will lead to very helpful maintaining the code because you don’t have to change the code at all the places where you have used you need to modify a function or class and this also come under coding standards of writing clean code.
We can also make our code look good and increase its uses by writing generic code. It has been noticed that developers write code specific to the functionality but when you take a closer look into the code an intelligent developer can see that the code can be refactored and put into a function or a class and can be used wherever it is needed.
Caching a crucial functionality
Caching is one of the crucial functionality Magento offers. It speeds up the site by loading content from the cache and there is some instance that it can cache the whole page. But it also has some cons, if a developer doesn’t know this or maybe forgot to clean the cache then it can create confusion. There are many instances when a developer modified the code and then went to the browser to see if the code works, but if he forgot to clean the cache then he may not see any difference despite making changes in the code. During theme development, a developer should always clean the cache to see the modification.
There are instances you will find that even after cleaning the cache the content is not updated at this time you should flush the cache.
Helper Classes
Helper classes contain specific and static methods for specific classes, they cannot be used in other classes. Sometimes the helper class contains multiple functions for multiple issues, which is not an ideal approach for object-oriented code. The Code should be written in such a manner that it contains appropriate methods for that class.
Working on layout
When developers work on layout it is best practice to extend layout which contains modifications according to requirements. Rather than duplicate layout and add extensive changes to a file.If developers require more customization in layout at that time, extending layout is not a good option. In that scenario, overriding that layout is a good option.
Working with Observer
Observer Overriding keeps the capability of modifying the Magento application, as they are injected dynamically into the execution flow of the Magento code, issues such as instability of the code can be caused if the observer overriding is not done properly.
For running your observer seamlessly in your Magento application, the following operation can be performed:
1)The complex computations should be avoided in the code, as more complex computations will slow down the observer, which will result in slow apppcation.
2)The logic contained in the observer should be useful and unnecessary logic should be avoided.
3) 3) The location of the observer places an important role in defining the efficiency of the observer, e.g., if an observer is needed for the frontend it should be declared in /etc/frontend/events.xml file rather than global /etc/events.xml file.
4)Invocation order in the observer should be avoided because due to this one observer may depend on another, which can cause delays in the overall function.
We hope the above blog helps you to clearly understand Magento 2 Coding Standards. In case of any kind of problem with the above code implementation, you can contact us or let us know in the comment section.
Thank You.