PHP Constructor and Destructor with Examples

A constructor is one of those PHP features you start using almost automatically once your classes become useful. Instead of creating an object and then remembering to set five different properties, you can make the object start life in a valid state.

The destructor sits at the other end of the object’s lifecycle. PHP calls it when the object is being destroyed. It can be useful for cleanup, although it should not become a last-minute dumping ground for important application logic.

PHP provides the __construct() and __destruct() magic methods for these two jobs.

PHP constructor and destructor quick answer

A PHP constructor is the __construct() method of a class. PHP calls it automatically when you create an object with new. It is commonly used to initialize properties and dependencies.

A destructor is the __destruct() method. PHP calls it when an object is destroyed, such as when its last reference disappears or during script shutdown. A destructor takes no arguments.

<?php

class Product
{
    public function __construct()
    {
        echo 'Product created';
    }

    public function __destruct()
    {
        echo 'Product destroyed';
    }
}

$product = new Product();

Creating $product automatically calls __construct(). The destructor is called later when PHP destroys the object.

PHP constructor with arguments

Constructors become more useful when they accept values required by the object. The values are passed immediately after the class name when the object is created.

<?php

class Product
{
    private string $name;
    private float $price;

    public function __construct(string $name, float $price)
    {
        $this->name = $name;
        $this->price = $price;
    }

    public function getDetails(): string
    {
        return $this->name . ' - $' . number_format($this->price, 2);
    }
}

$product = new Product('Wireless Mouse', 29.95);

echo $product->getDetails();

Here, the constructor requires a product name and price. An object cannot be created without supplying them. That is useful because the class does not have to deal with a half-initialized product later.

Constructor parameters can use PHP type declarations, default values and named arguments like normal PHP method parameters.

Constructor property promotion in PHP

For classes that mainly copy constructor arguments into properties, PHP 8 introduced constructor property promotion. It removes quite a lot of repetitive code.

The previous Product class can be shortened to this:

<?php

class Product
{
    public function __construct(
        private string $name,
        private float $price
    ) {
    }

    public function getDetails(): string
    {
        return $this->name . ' - $' . number_format($this->price, 2);
    }
}

$product = new Product('Wireless Mouse', 29.95);

echo $product->getDetails();

The $name and $price parameters are also declared as object properties and PHP assigns their values automatically. There is no need to declare the properties separately and repeat assignments such as $this->name = $name.

Property promotion is especially convenient for small value objects, configuration objects and classes that receive several dependencies through their constructor.

Calling a parent constructor

With PHP inheritance, when a child class defines its own constructor, PHP does not call the parent constructor automatically. If the parent constructor must run, call it explicitly with parent::__construct().

<?php

class User
{
    protected string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }
}

class AdminUser extends User
{
    private array $permissions;

    public function __construct(string $name, array $permissions)
    {
        parent::__construct($name);

        $this->permissions = $permissions;
    }

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

$admin = new AdminUser(
    'John',
    ['create-user', 'delete-user']
);

echo $admin->getName();

The child constructor handles its own $permissions property and delegates the common $name initialization to the parent class.

If the child class does not define a constructor, it inherits the parent constructor normally.

Can a PHP constructor return a value?

No. A constructor should initialize the object, not return another value.

The result of new ClassName() is always the newly created object. Do not use a return statement to try to return data from __construct().

If object creation can fail or needs more complex setup, a static factory method is often clearer.

<?php

class ApiClient
{
    private function __construct(
        private string $baseUrl
    ) {
    }

    public static function create(string $baseUrl): self
    {
        if ($baseUrl === '') {
            throw new InvalidArgumentException(
                'Base URL cannot be empty.'
            );
        }

        return new self($baseUrl);
    }
}

$client = ApiClient::create('https://api.example.com');

This pattern is not required for ordinary classes. It is useful when object creation needs validation or several setup steps before returning a usable instance.

How PHP destructors work

A destructor is declared with __destruct(). It takes no parameters.

<?php

class TemporaryFile
{
    public function __construct(
        private string $path
    ) {
        file_put_contents($this->path, 'Temporary data');
    }

    public function __destruct()
    {
        if (is_file($this->path)) {
            unlink($this->path);
        }
    }
}

$file = new TemporaryFile(
    sys_get_temp_dir() . '/php-example.txt'
);

In this example, the destructor removes a temporary file when PHP destroys the object.

This demonstrates the idea well, but important application behavior should not depend only on a destructor. Destructor timing can be affected by object references and script shutdown. Explicit cleanup is usually easier to reason about when timing matters.

When is a destructor called?

According to PHP’s constructor and destructor documentation, a destructor can run before the end of the script if the object is destroyed earlier.

<?php

class Connection
{
    public function __construct()
    {
        echo "Connection opened\n";
    }

    public function __destruct()
    {
        echo "Connection closed\n";
    }
}

$connection = new Connection();

unset($connection);

echo "Script continues\n";

Once unset() removes the last reference to the object, PHP can destroy it and call __destruct().

If other references to the same object still exist, removing one variable does not necessarily destroy the object.

<?php

class Demo
{
    public function __destruct()
    {
        echo "Object destroyed\n";
    }
}

$first = new Demo();
$second = $first;

unset($first);

echo "One reference still exists\n";

unset($second);

The destructor runs only after the remaining reference is removed.

This distinction is useful when debugging object lifecycle issues. unset($variable) removes a variable. It does not guarantee immediate object destruction if something else still references that object.

Calling a parent destructor

Destructor inheritance follows a rule similar to constructors. If a child class defines its own destructor, the parent destructor is not called automatically.

Call parent::__destruct() when the parent class also has cleanup work to perform.

<?php

class BaseLogger
{
    public function __destruct()
    {
        echo "Base logger cleanup\n";
    }
}

class FileLogger extends BaseLogger
{
    public function __destruct()
    {
        echo "File logger cleanup\n";

        parent::__destruct();
    }
}

$logger = new FileLogger();

Forgetting the parent call can leave part of the intended cleanup logic unused. This matters most when a base class owns a resource that the child class does not manage directly.

Do not use old-style PHP constructors

Older PHP code sometimes used a method with the same name as the class as its constructor.

<?php

class Product
{
    public function Product()
    {
        echo 'Old-style constructor';
    }
}

That syntax is obsolete. PHP 8 and later do not treat Product() as a constructor.

Use __construct() in modern PHP:

<?php

class Product
{
    public function __construct()
    {
        echo 'Modern constructor';
    }
}

This is particularly important when maintaining an old PHP application. A class-name method may look like a constructor at first glance, but on current PHP versions it is just an ordinary method unless something calls it explicitly.

Constructor and destructor best practices

Keep constructors focused on getting the object into a valid state. Passing required dependencies and initializing properties are good constructor responsibilities.

Avoid putting large amounts of work in a constructor. Database queries, remote API calls, file processing, and other expensive operations can make object creation harder to test and harder to control.

Use destructors for lightweight cleanup where automatic cleanup is genuinely useful. Do not rely on them for critical work such as saving important business data, committing transactions, sending required notifications, or recording something that absolutely must happen.

When cleanup must happen at a predictable point, an explicit method is usually clearer:

<?php

class ReportFile
{
    private bool $closed = false;

    public function close(): void
    {
        if ($this->closed) {
            return;
        }

        // Perform predictable cleanup here.

        $this->closed = true;
    }

    public function __destruct()
    {
        $this->close();
    }
}

This gives application code a clear close() method while keeping the destructor as a fallback.

Common constructor and destructor mistakes

Most problems with constructors and destructors are not syntax errors. They come from assumptions about when methods run and what they should be responsible for.

Forgetting to call the parent constructor

If both the parent and child define __construct(), the child must call parent::__construct() when the parent initialization is required.

<?php

class Account
{
    protected string $id;

    public function __construct(string $id)
    {
        $this->id = $id;
    }
}

class PremiumAccount extends Account
{
    private int $level;

    public function __construct(string $id, int $level)
    {
        parent::__construct($id);

        $this->level = $level;
    }
}

Doing too much work in the constructor

A constructor that performs several database queries, API requests, or file operations makes object creation expensive and harder to test.

Prefer initializing the object in the constructor and moving larger operations into normal methods.

Expecting unset() to always call the destructor immediately

unset() removes a variable. If another reference to the same object still exists, the object remains alive and its destructor does not run yet.

Depending on a destructor for critical work

Destructors are useful for cleanup, but they are a poor place for work that must definitely happen at a precise point in the request.

If something is important enough that failure would affect application data, call it explicitly instead of relying only on __destruct().

Constructor vs destructor in PHP

Constructor Destructor
__construct() __destruct()
Runs when an object is created Runs when an object is destroyed
Can accept parameters Cannot accept parameters
Commonly initializes properties and dependencies Commonly performs lightweight cleanup
Can use constructor property promotion Has no equivalent property-promotion feature
A child constructor must explicitly call the parent constructor when needed A child destructor must explicitly call the parent destructor when needed

Frequently asked questions

Can a PHP class have more than one constructor?

No. PHP does not support constructor overloading by defining several __construct() methods with different parameter lists.

You can use optional parameters, named arguments, or static factory methods when you need different ways to create an object.

Is __construct() required in every PHP class?

No. Define a constructor only when the object needs initialization when it is created.

A class without __construct() can still be instantiated normally.

Is __destruct() required?

No. Most PHP classes do not need a destructor.

Add one only when the class owns cleanup work that makes sense at object destruction time.

Can I manually call __construct() or __destruct()?

They are methods and can technically be called like methods when visibility permits, but doing so usually gives the wrong object-lifecycle semantics.

Create objects with new and expose normal methods for explicit initialization or cleanup when you need those operations independently.

What happens if the constructor throws an exception?

If __construct() throws an exception, object creation does not complete successfully. The caller should handle the exception where appropriate.

<?php

class Percentage
{
    public function __construct(
        private float $value
    ) {
        if ($value < 0 || $value > 100) {
            throw new InvalidArgumentException(
                'Percentage must be between 0 and 100.'
            );
        }
    }
}

try {
    $percentage = new Percentage(150);
} catch (InvalidArgumentException $exception) {
    echo $exception->getMessage();
}

Constructor validation is useful when an object should never exist in an invalid state.

Conclusion

Use __construct() to make sure an object starts with the data and dependencies it needs. For simple classes, constructor property promotion keeps this code compact without hiding what is happening.

Use __destruct() more cautiously. It is useful for lightweight cleanup, but explicit cleanup methods are better when timing or reliability matters.

The key detail to remember is that constructors control object initialization, while destructors respond to object destruction. Keeping both responsibilities small and predictable makes PHP classes easier to understand and maintain.

Photo of Vincy, PHP developer
Written by Vincy Last updated: August 12, 2026
I'm a PHP developer with 20+ years of experience and a Master's degree in Computer Science. I build and improve production PHP systems for eCommerce, payments, webhooks, and integrations, including legacy upgrades (PHP 5/7 to PHP 8.x).

Continue Learning

These related tutorials may help you continue learning.

Leave a Reply

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

Explore topics
Need PHP help?