This deep dive focuses on how Drupal actually uses PHP and OOP, not generic PHP theory. Everything here is aligned with Drupal core patterns, Acquia exam expectations, and real project usage.
Module 4.1 validates that you:
- Can read and understand Drupal core code
- Know why Drupal moved from procedural PHP to OOP
- Can choose the correct OOP pattern in a scenario
Acquia is not testing syntax. It is testing architectural judgment.
PHP in Drupal (what changed after Drupal 8)
Before Drupal 8:
- Mostly procedural PHP
- Heavy use of hooks
Drupal 8+ (including Drupal 11):
- Built on Symfony
- Fully object-oriented
- Services, controllers, plugins everywhere
Hooks still exist, but OOP is primary.
Classes in Drupal
What a class represents
In Drupal, classes represent roles in the system:
- Controller = handles request
- Service = reusable logic
- Plugin = swappable feature
Core example: Controller
namespace Drupal\node\Controller;
use Drupal\Core\Controller\ControllerBase;
class NodeViewController extends ControllerBase {
}
Interview sentence
“Controllers in Drupal are classes that return responses or render arrays.”
Objects (instances)
Drupal rarely creates objects using new directly.
Instead:
- Objects are created by the container
- Injected via dependency injection
Core philosophy:
Let Drupal manage object creation
Interfaces (contracts)
Why Drupal uses interfaces
Interfaces ensure:
- Consistency
- Replaceability
- Testability
Core example
use Drupal\Core\Cache\CacheableDependencyInterface;
class Example implements CacheableDependencyInterface {
}
If a class implements this interface, Drupal knows it provides cache metadata.
Exam signal
If caching is mentioned, interfaces often matter.
Inheritance (extends)
How Drupal uses inheritance
Drupal uses inheritance for:
- Shared behavior
- Base functionality
Core example
class ExampleController extends ControllerBase {
}
Why this matters:
- Access to services
- Shared helper methods
Exam signal
If a class needs Drupal services, extending ControllerBase is expected.
Composition (preferred over inheritance)
What composition means
Using services instead of extending classes.
Drupal prefers:
- Small classes
- Injected dependencies
Core example
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
Exam signal
If reuse is required, composition is preferred.
Namespaces (PSR-4)
Why namespaces matter in Drupal
Namespaces:
- Map classes to file paths
- Enable autoloading
Example mapping:
- File:
src/Controller/ExampleController.php - Namespace:
namespace Drupal\example\Controller;
Common mistake
Namespace mismatch causes class not found errors.
Dependency Injection (Drupal core pattern)
Core controller example
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
class ExampleController extends ControllerBase {
protected $entityTypeManager;
public function __construct(EntityTypeManagerInterface $entityTypeManager) {
$this->entityTypeManager = $entityTypeManager;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager')
);
}
}
Why Drupal uses this:
- Testable code
- Replaceable services
- Clean architecture
Exam trap
Using \Drupal::service() inside classes instead of DI.
Static service access (when allowed)
\Drupal::service('logger.factory');
Allowed only:
- In procedural code
- In legacy hooks
Not recommended in:
- Controllers
- Services
Procedural code still exists (hooks)
Drupal still uses procedural hooks.
Example:
function example_entity_presave(\Drupal\Core\Entity\EntityInterface $entity) {
}
Hooks:
- React to events
- Do not replace OOP
OOP + Hooks working together
Drupal architecture:
- OOP for structure
- Hooks for extension
Correct mental model:
Hooks notify, classes handle logic.
Error handling and logging
Drupal uses services for logging.
Core example:
$this->logger('example')->error('Something went wrong');
Avoid:
echoprint_r
Performance considerations (4.1 context)
Good OOP:
- Reuse services
- Avoid heavy constructors
- Inject only what you need
Bad OOP:
- Loading entities in constructors
- Static service calls everywhere
Security considerations (4.1 context)
- Do not trust input
- Use APIs
- Avoid global state
OOP helps security by:
- Isolating responsibilities
- Making code testable
Common Acquia exam traps (Module 4.1)
- Procedural PHP instead of OOP
- Using
newfor services - Using
\Drupal::service()inside classes - Ignoring interfaces
- Namespace mismatch