Drupal Coding Standards are a shared rulebook for how Drupal code should be written. They make sure that code written by thousands of developers looks consistent, is easy to read, secure, and maintainable.
Think of it like traffic rules. Everyone follows the same rules so things do not crash.
1. Technical explanation
Drupal coding standards are based on:
- PHP standards (PSR where applicable)
- Drupal Core conventions
- Security best practices
- Performance and maintainability principles
These standards are enforced in real projects using:
- PHP CodeSniffer (phpcs)
- Drupal Coder module ruleset
Acquia exams test whether you:
- Recognize correct Drupal-style code
- Can spot bad practices
- Choose the safest and most maintainable option
Acquia is not testing memorization. It is testing judgment.
Security implication:
Consistent standards reduce injection risks, unsafe globals, and accidental data leaks.
Performance implication:
Standardized code encourages caching, service usage, and testability.
2. PHP Coding Standards in Drupal
Namespaces and classes
namespace Drupal\example_module\Controller;
use Drupal\Core\Controller\ControllerBase;
class ExampleController extends ControllerBase {
public function content() {
return ['#markup' => $this->t('Hello World')];
}
}
Why this is correct:
- Uses a namespace
- Class name matches file name
- Extends ControllerBase
- No global functions
Bad example
class example_controller {
function content() {
return 'Hello';
}
}
Why this is wrong:
- No namespace
- Wrong class naming
- No return render array
- Not translatable
Exam trap:
If you see plain strings returned instead of render arrays, it is usually wrong.
Methods and visibility
Drupal requires explicit visibility.
Good:
public function build(): array {
return [];
}
Bad:
function build() {
return [];
}
Why:
Explicit visibility improves readability and prevents accidental overrides.
3. Drupal-Specific Standards
Hooks
Hooks are procedural by design and are allowed only in specific places.
Allowed:
function example_module_help($route_name, $route_match) {
if ($route_name === 'help.page.example_module') {
return t('Help text');
}
}
Why this is correct:
- Hook functions must be procedural
- Function name matches module name
Not allowed:
Putting business logic inside hooks.
Exam trap:
Hooks are glue code, not logic containers.
Controllers
Controllers must:
- Return render arrays or responses
- Use dependency injection
Good:
class ExampleController extends ControllerBase {
public function page(): array {
return ['#markup' => $this->t('Example')];
}
}
Bad:
public function page() {
echo 'Example';
exit;
}
Security implication:
Echo and exit bypass Drupal rendering and security layers.
Plugins
Plugins must:
- Use annotations
- Extend correct base classes
Example:
/**
* @Block(
* id = "example_block",
* admin_label = @Translation("Example block")
* )
*/
class ExampleBlock extends BlockBase {
}
Exam trap:
Missing annotations means the plugin will not be discovered.
4. File and Directory Naming Conventions
PHP files
- Class name must match file name
- One class per file
Correct:
ExampleController.php
Incorrect:
example.controller.php
Module structure
example_module/
src/
Controller/
Plugin/
Form/
Why:
Autoloading depends on predictable structure.
5. YAML Standards
.info.yml
Good:
name: Example Module
type: module
core_version_requirement: ^10
package: Custom
Bad:
Name: example
Why:
YAML keys are case-sensitive.
.routing.yml
Good:
example_module.page:
path: '/example'
defaults:
_controller: '\\Drupal\\example_module\\Controller\\ExampleController::page'
_title: 'Example'
requirements:
_permission: 'access content'
Security implication:
Permissions must always be declared.
Exam trap:
Missing permissions is always wrong.
.services.yml
Good:
services:
example_module.example_service:
class: Drupal\example_module\ExampleService
Why:
Services must be defined to be injected.
6. Procedural Code vs OOP
When procedural is allowed
- Hooks
- .module file glue code
When OOP is required
- Business logic
- Controllers
- Forms
- Services
Exam rule:
If logic is reusable or testable, it belongs in a service.
7. Dependency Injection Standards
Correct
public function __construct(LoggerChannelFactoryInterface $logger_factory) {
$this->logger = $logger_factory->get('example');
}
Why:
- Testable
- Replaceable
- Clear dependencies
8. Static Calls (\Drupal::)
Allowed
- Legacy glue code
- Very small scripts
Not allowed
- Controllers
- Services
- Plugins
Bad:
\Drupal::database()->select('node');
Good:
Inject the database connection.
Exam trap:
Static calls are a last resort.
9. Logging, Errors, and Messaging
Logging
Correct:
$this->logger->error('Something failed');
Incorrect:
print 'Error';
Security implication:
Do not expose internal errors to users.
Messaging
Use:
$this->messenger()->addStatus($this->t('Saved successfully'));
Never:
echo 'Saved';
10. Commenting and Documentation
File header
/**
* @file
* Provides example functionality.
*/
Function documentation
/**
* Builds the example page.
*
* @return array
* Render array.
*/
Why:
Helps IDEs, reviewers, and future developers.
11. Common Violations in Real Projects
- Logic inside hooks
- Static service calls everywhere
- Missing permissions
- Hardcoded strings
- No dependency injection
Exam trap:
The answer with fewer shortcuts is usually correct.
12. How Acquia Tests Coding Standards
Scenario-based questions:
- Which implementation is more Drupal-like
- Which code is more secure
- Which solution is more maintainable
They test principles, not syntax memorization.
Final Exam Revision Checklist
- Uses namespaces and PSR structure
- No echo or exit
- Render arrays returned
- Permissions defined
- Services injected
- Hooks used only as glue
- Logging instead of printing
One-Sentence Takeaway
Drupal coding standards exist to make code secure, readable, testable, and predictable across teams.
Quick Mental Checklist for the Exam
Is it secure
Is it injectable
Is it testable
Is it Drupal-style
Is it future-proof