CodeBlanks Logo Icon CodeBlanks

Class type declaration

PHP course · Intermediate · Lesson 10/115

Learn to declare a class type on a constructor parameter so it only accepts that class.

Class type declaration

When you add a type declaration to a constructor parameter, PHP accepts only values of that type. If you write a class name as the type, the parameter only takes instances of that class:

class Engine {
    public function start(): void {
        echo "Started\n";
    }
}

class Car {
    public function __construct(Engine $engine) {
        $this->engine = $engine;
    }
}

Here Engine $engine says the parameter may only be an instance of the Engine class. Pass the wrong type and PHP throws a TypeError. This pattern shows explicitly that a class needs another class, and is called dependency injection.

Dependency injection

When a class needs another class to do its job, the cleanest approach is to take that need from the outside as a constructor parameter. This is called dependency injection.

$engine = new Engine();
$car = new Car($engine);

Here you first create the Engine instance, then pass it to the Car instance. The Car class does not create the Engine itself; it uses the one given from outside. This makes the code easier to test: you can pass a mock Engine during testing.

Without a type declaration you might accidentally pass an array or a string; the type declaration prevents that mistake.

Exercise Dependency injection with Logger and Service

Define two classes. First Logger: it should have a method public function log(string $message): void that prints echo "[LOG] " . $message . "\n"; in the body. Second Service: declare a property public $logger;; its constructor should take a Logger instance with the signature __construct(Logger $logger) and perform $this->logger = $logger;. Outside the classes call $logger = new Logger();, $service = new Service($logger); and $service->logger->log("Service ready");.

Show example solution
public function log(string $message): void { echo "[LOG] " . $message . "\n"; }. Inside Service: public $logger; and public function __construct(Logger $logger) { $this->logger = $logger; }. Then $logger = new Logger();, $service = new Service($logger); and $service->logger->log("Service ready");.
Example solution:
<?php
// Define the Logger and Service classes
class Logger {
    public function log(string $message): void {
        echo "[LOG] " . $message . "\n";
    }
}

class Service {
    public $logger;

    public function __construct(Logger $logger) {
        $this->logger = $logger;
    }
}

$logger = new Logger();
$service = new Service($logger);
$service->logger->log("Service ready");

Test yourself

  1. Match the concepts

    Engine $engine
    class-typed parameter
    TypeError
    wrong type error
    new Car($engine)
    passing the dependency
    dependency injection
    external dependency
  2. What does the Engine $engine type declaration provide?

    • The parameter can take any value
    • The parameter can only be an Engine instance
    • The parameter must be an array
    • The parameter must be null
    Show answer

    The parameter can only be an Engine instance — Correct. A class-name type declaration restricts the parameter to instances of that class only.

  3. Complete the type declaration

        public function __construct(____ $engine) {
            $this->engine = $engine;
        }
    Show answer
        public function __construct(Engine $engine) {
            $this->engine = $engine;
        }

All lessons in Intermediate