Davor’s PHP Constructor — Real-World Examples and Patterns

Davor’s PHP Constructor: A Beginner’s GuideA constructor is a special method in object-oriented programming used to initialize newly created objects. In PHP, constructors set up object state, inject dependencies, and prepare resources. This guide explains constructors in PHP using a clear, practical approach, with examples and common patterns, so beginners can start writing clean, predictable class initializations.


What is a constructor?

A constructor is a method automatically called when you create a new instance of a class. It typically configures the object’s initial properties, validates input, and performs any setup required before the object is used.

  • In PHP, the constructor method is named __construct().
  • It runs once per object upon instantiation: new ClassName(…).

Example — simplest constructor

<?php class User {     public $name;     public function __construct($name) {         $this->name = $name;     } } $user = new User('Davor'); echo $user->name; // Davor 

Why use constructors?

Constructors provide predictable, centralized initialization. Benefits include:

  • Ensuring required dependencies or values are set.
  • Reducing the chance of using an uninitialized object.
  • Encapsulating setup logic (e.g., opening a DB connection, configuring defaults).
  • Making classes easier to test by clarifying required inputs.

Constructor visibility and default values

Constructors can have visibility modifiers: public, protected, or private.

  • public: any code can instantiate the class.
  • protected: only the class itself and subclasses can instantiate; often used with factory methods.
  • private: restricts instantiation to within the class (singleton pattern or static factory).

You can provide default parameter values to make some arguments optional.

Example

<?php class Logger {     protected $level;     public function __construct($level = 'info') {         $this->level = $level;     } } 

Type declarations and strict typing

Use type hints for constructor parameters to improve correctness and readability. With strict typing enabled, PHP enforces types.

Example with strict types

<?php declare(strict_types=1); class Product {     public string $sku;     public float $price;     public function __construct(string $sku, float $price) {         $this->sku = $sku;         $this->price = $price;     } } 

Type declarations can be class/interface types, arrays, callable, scalar types (int, string, float, bool), or union types (PHP 8.0+). Use nullable types with ?Type.


Property promotion (PHP 8.0+)

PHP 8 introduced constructor property promotion to reduce boilerplate. You can declare and initialize properties directly in the constructor signature.

Example

<?php class Point {     public function __construct(         public float $x = 0.0,         public float $y = 0.0     ) {} } $p = new Point(1.5, 2.5); echo $p->x; // 1.5 

This replaces the common pattern of separately declaring properties and assigning them in the constructor.


Dependency Injection via constructor

Constructor injection is a common pattern where required collaborators are passed in through the constructor. This improves testability and decoupling.

Example

<?php interface MailerInterface {     public function send(string $to, string $subject, string $body): bool; } class UserNotifier {     private MailerInterface $mailer;     public function __construct(MailerInterface $mailer) {         $this->mailer = $mailer;     }     public function notify(string $email, string $message): bool {         return $this->mailer->send($email, 'Notification', $message);     } } 

In tests, you can pass a mock MailerInterface implementation.


Calling parent constructors

When a subclass defines its own constructor, it must call parent::__construct(…) if the parent needs initialization.

Example

<?php class Animal {     protected string $name;     public function __construct(string $name) {         $this->name = $name;     } } class Dog extends Animal {     private string $breed;     public function __construct(string $name, string $breed) {         parent::__construct($name);         $this->breed = $breed;     } } 

If you forget to call the parent constructor, parent properties might remain unset.


Lazy initialization vs constructor work

Constructors should do necessary, fast setup. Avoid heavy operations (long network calls, heavy file parsing) in constructors because:

  • They run on every instantiation.
  • They make object creation slow and harder to test.
  • They can hide errors during simple object creation.

Use lazy initialization for expensive resources: initialize on first use, not in the constructor.

Lazy example

<?php class HeavyLoader {     private ?array $data = null;     public function getData(): array {         if ($this->data === null) {             // expensive operation             $this->data = $this->loadFromDisk();         }         return $this->data;     } } 

Error handling in constructors

If a constructor fails to create a valid object, throw an exception. Don’t return null or silence errors—PHP constructors can’t return values.

Example

<?php class Config {     public function __construct(string $path) {         if (!is_readable($path)) {             throw new InvalidArgumentException("Config file not readable: $path");         }         // load config...     } } 

Catching exceptions around object creation allows callers to handle failures gracefully.


Common patterns and anti-patterns

  • Favor constructor injection for required dependencies.
  • For optional dependencies, consider setter injection or provide sensible defaults.
  • Avoid starting long-running processes (threads, continuous loops) inside constructors.
  • Don’t perform side-effectful operations (sending emails, writing files) unless absolutely necessary; prefer methods that the caller invokes explicitly.

Practical examples

  1. Simple service class with dependency injection “`php <?php class Database { public function connect(): void { /* … */ } }

class UserRepository {

private Database $db; public function __construct(Database $db) {     $this->db = $db; } 

}


2) Using property promotion and validation ```php <?php class Account {     public function __construct(         public string $id,         private float $balance = 0.0     ) {         if ($balance < 0) {             throw new InvalidArgumentException('Balance cannot be negative');         }     } } 
  1. Factory method with protected constructor

    <?php class ApiClient { private function __construct(private string $token) {} public static function fromEnv(): self {     $token = getenv('API_TOKEN') ?: '';     return new self($token); } } 

Testing constructors

  • Keep constructor logic minimal to simplify testing.
  • Use mocks/stubs for dependencies injected into constructors.
  • For classes with complex setup, provide factory helpers in tests to create objects in a valid state.

Performance and memory considerations

Constructors are called frequently; avoid allocating large structures or loading big files unless needed. Promote immutability for predictable objects: set properties in constructor and avoid changing state later when possible.


Summary checklist (for beginners)

  • Use __construct() to initialize required state.
  • Prefer constructor injection for required dependencies.
  • Use property promotion (PHP 8+) to reduce boilerplate.
  • Keep heavy work out of constructors; use lazy initialization.
  • Throw exceptions on unrecoverable constructor errors.
  • Call parent::__construct(…) when extending classes that need initialization.

This guide covered theory, syntax, common patterns, and practical examples to help you start using PHP constructors confidently.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *