Module 4.1 – PHP & Object-Oriented Programming in Drupal

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:

  • echo
  • print_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 new for services
  • Using \Drupal::service() inside classes
  • Ignoring interfaces
  • Namespace mismatch