| name | drupal-coding-standards |
| description | PHPCS, PHPStan, naming conventions, and code style enforcement for Drupal 10/11. Use when checking coding standards, running static analysis, or enforcing code quality. |
Drupal Coding Standards
Always run PHPCS before committing. Never skip static analysis. Use declare(strict_types=1) in every PHP file. Prefer final classes unless explicitly designed for extension. Avoid deep nesting — use guard clauses and early returns.
Validation Commands
./vendor/bin/phpcs --standard=Drupal,DrupalPractice web/modules/custom/my_module/
./vendor/bin/phpcbf --standard=Drupal web/modules/custom/my_module/
./vendor/bin/phpstan analyse web/modules/custom/my_module/
drupal-check web/modules/custom/my_module/
composer audit
Required Code Patterns
File Headers
<?php
declare(strict_types=1);
namespace Drupal\my_module;
Class Declaration
final class ContentManager implements ContentManagerInterface {
Constructor
public function __construct(
private readonly EntityTypeManagerInterface $entityTypeManager,
private readonly LoggerInterface $logger,
) {}
Naming Conventions
| Element | Convention | Example |
|---|
| Local variables | $snake_case | $user_name |
| Class properties | $lowerCamelCase | $this->entityManager |
| Classes | PascalCase | ContentManager |
| Interfaces | PascalCase + Interface | ContentManagerInterface |
| Constants | UPPER_SNAKE_CASE | MAX_RETRY_COUNT |
| Services | module.service_name | my_module.content_manager |
| Hooks | module_hook_name | my_module_form_alter |
Anti-Patterns to Report
| Anti-Pattern | Fix |
|---|
foreach with nested if/break/continue | array_filter/array_map/array_reduce |
| Deep nesting (3+ levels) | Guard clauses, early returns |
| Non-final classes without reason | Declare final by default |
Getters/setters where public readonly works | Use public readonly |
\Drupal:: calls in classes | Constructor dependency injection |
PHP json_encode/decode | \GuzzleHttp\Utils::jsonDecode/jsonEncode |
| "Service" namespace | Use logical groupings |
Catching \Exception | Catch narrowest exception type |
PHPDoc Standards
public function loadByCategory(int $category_id, int $limit = 10): array {
Module Structure
modules/custom/my_module/
my_module.info.yml
my_module.module
my_module.services.yml
my_module.routing.yml
my_module.permissions.yml
config/
install/
schema/
src/
Controller/
Form/
Plugin/
Block/
EventSubscriber/
tests/
src/
Unit/
Kernel/
Functional/