PHP Constructor

Yo Yogesh.M Updated 17 Oct 2026
6 min read ·Lesson 60 of 109
In this post

What Is a Constructor? In simple terms: A constructor is a special method that runs automatically when an object is created with new . It receives the data the object needs and sets it up, so the obje

What Is a Constructor?

In simple terms: A constructor is a special method that runs automatically when an object is created with new. It receives the data the object needs and sets it up, so the object is complete and valid from the very first moment.

Technically: A constructor is a method named __construct(). PHP calls it immediately after allocating a new object, passing along the arguments given to new ClassName(...). It typically assigns properties, validates input, and stores dependencies. A constructor does not return a value; the result of new is always the object itself.

Why Constructors Matter

Without a constructor, objects are created empty and filled in afterwards:

$user = new User();
$user->name = 'Asha';
// forgot to set the email...

Between creation and assignment — or forever, if a line is forgotten — the object is incomplete. A constructor makes the required data part of creating the object:

$user = new User('Asha', 'asha@example.com');   // cannot be created without both values

Defining a Constructor

Syntax

class ClassName
{
    public function __construct(Type $param1, Type $param2 = default)
    {
        // initialize properties
    }
}

Example

<?php
class User
{
    private string $name;
    private string $email;

    public function __construct(string $name, string $email)
    {
        $name = trim($name);

        if ($name === '') {
            throw new InvalidArgumentException('Name is required.');
        }

        if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
            throw new InvalidArgumentException("Invalid email: $email");
        }

        $this->name = $name;
        $this->email = strtolower($email);
    }

    public function name(): string
    {
        return $this->name;
    }

    public function email(): string
    {
        return $this->email;
    }
}

$user = new User('  Asha ', 'Asha@Example.com');
echo $user->name() . ' <' . $user->email() . ">\n";

foreach ([['', 'bala@example.com'], ['Bala', 'bala@']] as [$name, $email]) {
    try {
        new User($name, $email);
    } catch (InvalidArgumentException $e) {
        echo "Error: " . $e->getMessage() . "\n";
    }
}

Output

Asha <asha@example.com>
Error: Name is required.
Error: Invalid email: bala@

How It Works

  1. new User(' Asha ', 'Asha@Example.com') creates the object and calls __construct() with the two arguments.
  2. The constructor normalizes the values (trims the name, lowercases the email) and validates them.
  3. If validation fails, the constructor throws an exception. The new expression then does not produce an object at all — invalid users simply cannot exist.
  4. Because the typed properties are always assigned in the constructor, they can never be read in an uninitialized state.

Missing Arguments

Calling new User('Asha') without the email throws an ArgumentCountError, just like calling a function with too few arguments. Required constructor parameters are therefore checked by PHP itself.


Optional Parameters and Named Arguments

Constructor parameters support defaults and named arguments like any function:

<?php
class Notification
{
    private string $channel;
    private string $priority;
    private ?DateTimeImmutable $sendAt;

    public function __construct(
        private string $message,
        string $channel = 'email',
        string $priority = 'normal',
        ?DateTimeImmutable $sendAt = null,
    ) {
        $this->channel = $channel;
        $this->priority = $priority;
        $this->sendAt = $sendAt;
    }

    public function describe(): string
    {
        $when = $this->sendAt?->format('d M Y H:i') ?? 'immediately';
        return "[{$this->priority}] via {$this->channel}, $when: {$this->message}";
    }
}

echo (new Notification('Your order has shipped'))->describe() . "\n";
echo (new Notification('Payment failed', priority: 'high', channel: 'sms'))->describe() . "\n";
echo (new Notification('Class reminder', sendAt: new DateTimeImmutable('2026-10-17 18:30')))->describe() . "\n";

Output

[normal] via email, immediately: Your order has shipped
[high] via sms, immediately: Payment failed
[normal] via email, 17 Oct 2026 18:30: Class reminder
  • Defaults cover the common case, so simple notifications need only a message.
  • Named arguments make calls with several optional settings readable and let callers skip parameters.
  • private string $message in the parameter list is constructor property promotion — it declares and assigns the property in one step (see Constructor Property Promotion).

Named Constructors (Static Factory Methods)

Sometimes an object can be created from different kinds of input. A constructor can have only one signature, but static factory methods with descriptive names can offer several ways to create an object:

<?php
final class Money
{
    private function __construct(private int $paise) {}

    public static function fromRupees(float $rupees): self
    {
        return new self((int) round($rupees * 100));
    }

    public static function fromPaise(int $paise): self
    {
        return new self($paise);
    }

    public function add(Money $other): self
    {
        return new self($this->paise + $other->paise);
    }

    public function format(): string
    {
        return '₹' . number_format($this->paise / 100, 2);
    }
}

$total = Money::fromRupees(1299.50)->add(Money::fromPaise(50));
echo $total->format() . "\n";

try {
    $money = new Money(500);
} catch (Error $e) {
    echo $e->getMessage() . "\n";
}

Output

₹1,300.00
Call to private Money::__construct() from global scope

Why This Design Helps

  1. The private constructor forces callers to use the factories, whose names say what the number means — fromRupees(1299.50) versus fromPaise(50). With a public constructor, new Money(500) would be ambiguous: 500 rupees or 500 paise?
  2. Money is stored internally as integer paise, which avoids floating-point rounding errors in calculations.
  3. add() returns a new object instead of changing the existing one, making Money an immutable value object.

DateTimeImmutable::createFromFormat() is a built-in example of a named constructor.


Constructors and Dependencies

Objects often need other objects — services — to do their work. The constructor is the natural place to receive them. This is called dependency injection:

<?php
interface Notifier
{
    public function send(string $to, string $message): void;
}

final class ConsoleNotifier implements Notifier
{
    public function send(string $to, string $message): void
    {
        echo "To $to: $message\n";
    }
}

final class OrderService
{
    public function __construct(private Notifier $notifier) {}

    public function confirm(int $orderId, string $email): void
    {
        // ... save the confirmation ...
        $this->notifier->send($email, "Order #$orderId is confirmed.");
    }
}

$service = new OrderService(new ConsoleNotifier());
$service->confirm(501, 'asha@example.com');

Output

To asha@example.com: Order #501 is confirmed.

OrderService does not create its notifier; it receives one. In production, an email or SMS notifier is passed in; in tests, a fake one. Frameworks build and inject these dependencies automatically through a service container.

Since PHP 8.1, parameter defaults may also create objects: public function __construct(private Notifier $notifier = new ConsoleNotifier()).


What Belongs in a Constructor

DoAvoid
Assign required data and dependenciesHeavy work: database queries, HTTP requests, file processing
Validate and normalize inputPrinting output
Establish a valid initial stateStarting long-running processes

Constructors should be fast and predictable. If creating an object requires loading data, do that in a separate method or a factory that then passes the loaded data to the constructor.


Common Mistakes

Misspelling __construct

Effect: __constuct() or _construct() is just an ordinary method that never runs automatically.

Fix: Use exactly two underscores: __construct.

Old-Style Constructors

Effect: In PHP 8, a method with the same name as the class (function User()) is no longer a constructor.

Fix: Always use __construct().

Leaving Objects Half-Initialized

Effect: Required properties are set later (or never), causing uninitialized-property errors.

Fix: Require essential data as constructor parameters.

Returning Values From the Constructor

Effect: The return value is ignored; new always produces the object.

Fix: Use static factory methods when you need alternative creation logic.

Doing Too Much Work

Effect: Slow, untestable object creation with hidden side effects.

Fix: Keep constructors simple; move work into methods or factories.


Best Practices

  • Require all essential data in the constructor so objects are always valid.
  • Validate and normalize input in the constructor and throw exceptions for invalid data.
  • Receive dependencies through the constructor instead of creating them inside the class.
  • Use named constructors (static factories) when there are several meaningful ways to create an object.
  • Keep constructors free of heavy work and side effects.

Official reference: https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators
Ask about this post
AI Ask about this post

Ask questions about PHP Constructor and get answers drawn from it.

Signed-in readers only.