Sling Academy
Home/PHP/How to Create Immutable Objects in PHP

How to Create Immutable Objects in PHP

Last updated: January 10, 2024

Overview

Immutable objects are objects whose state cannot be modified after they are created. This concept can be beneficial for writing more predictable and reliable software, and you can implement it in PHP using certain principles and techniques. This tutorial will guide you through these techniques, from basic to advanced, to help you create immutable objects in PHP.

Introduction to Immutability

Before diving into the how-to, let’s clarify what immutable objects are and why they are important. An immutable object is an instance of a class that cannot be changed once it’s created. Any method that might alter its state will return a new instance of the class with the changed values. This is in contrast to mutable objects, which can be modified after creation.

Immutability is a core concept in many functional programming languages, and it’s valued because it leads to easier-to-understand code, and reduces the risk of side effects and concurrency issues. In PHP, which is predominantly a mutable language, achieving immutability requires discipline and clear design patterns.

Creating Basic Immutable Objects

To start creating an immutable object, you must design your class so that once an object is constructed, its state can’t change. A basic approach might look something like this:

<?php
class ImmutablePoint {
    private float $x;
    private float $y;

    public function __construct(float $x, float $y) {
        $this->x = $x;
        $this->y = $y;
    }

    public function getX(): float {
        return $this->x;
    }

    public function getY(): float {
        return $this->y;
    }

    public function moveTo(float $newX, float $newY): ImmutablePoint {
        return new self($newX, $newY);
    }
}

// Usage
$point = new ImmutablePoint(1.0, 2.0);
$newPoint = $point->moveTo(3.0, 4.0);
?>

In the above example, ImmutablePoint doesn’t offer any methods that change its state after it’s instantiated. Methods that require a state change return a new instance instead.

Handling Internal Arrays

When dealing with arrays or objects within our immutable class, we must ensure that these too are immutable, or they can lead to inadvertent side effects. One common mistake is to provide direct access to these internal structures, like this:

// Incorrect way to expose internal arrays - MUTABLE
class MutableWrapper {
    private array $data;

    public function __construct(array $data) {
        $this->data = $data;
    }

    public function getData(): array {
        return $this->data; // This is mutable
    }

    ... // Other code
}

// Correct way using immutability pattern
class ImmutableWrapper {
    private array $data;

    public function __construct(array $data) {
        $this->data = $data;
    }

    public function getData(): array {
        return $this->data;
    }

    public function withData(array $newData): ImmutableWrapper {
        return new self(array_merge($this->data, $newData));
    }
}
?>

In the corrected example, any change to data results in a new object being returned with the modified array, leaving the original object’s array untouched.

Advanced Immutability Patterns

For more advanced immutability, you can implement a class that handles its dependencies in an immutable way. This means that not only the properties of the class but also any referenced objects must be immutable. To achieve this, make sure you use immutable objects as dependencies or make defensive copies when necessary.

<?php
class ImmutableDependency {
    private ImmutablePoint $point;

    ... // Other code

    public function __construct(ImmutablePoint $point) {
        // Make a copy to ensure immutability
        $this->point = new ImmutablePoint($point->getX(), $point->getY());
    }

    ... // Other code
}

// Usage
$originalPoint = new ImmutablePoint(1.0, 2.0);
$dependencyObject = new ImmutableDependency($originalPoint);

// $originalPoint remains unchanged even if $dependencyObject changes internally
?>

By using this pattern, you effectively guarantee the immutability of your object’s entire object graph.

Using Immutability in Practice

In practice, immutability can be used to create robust, maintainable, and concurrent software. PHP 8 introduced the readonly keyword, which can make enforcing immutability somewhat easier. Additionally, consider using value objects, embrace returning new instances instead of mutating existing ones, favor composition over inheritance, and when needed, make deep copies of mutable dependencies.

Conclusion

Immutability in PHP is a powerful concept that, when implemented, can make your code more predictable and easier to understand. While PHP does not natively support immutability, you can achieve it through careful class design and object composition. By following the principles illustrated in this tutorial, you’ll be well on your way to writing safer and more reliable PHP applications.

Next Article: How to Implement Autoloading in PHP

Previous Article: How to Work with Final Classes and Methods in PHP

Series: PHP Data Structure Tutorials

PHP

You May Also Like

  • Pandas DataFrame.value_counts() method: Explained with examples
  • Constructor Property Promotion in PHP: Tutorial & Examples
  • Understanding mixed types in PHP (5 examples)
  • Union Types in PHP: A practical guide (5 examples)
  • PHP: How to implement type checking in a function (PHP 8+)
  • Symfony + Doctrine: Implementing cursor-based pagination
  • Laravel + Eloquent: How to Group Data by Multiple Columns
  • PHP: How to convert CSV data to HTML tables
  • Using ‘never’ return type in PHP (PHP 8.1+)
  • Nullable (Optional) Types in PHP: A practical guide (5 examples)
  • Explore Attributes (Annotations) in Modern PHP (5 examples)
  • An introduction to WeakMap in PHP (6 examples)
  • Type Declarations for Class Properties in PHP (5 examples)
  • Static Return Type in PHP: Explained with examples
  • PHP: Using DocBlock comments to annotate variables
  • PHP: How to ping a server/website and get the response time
  • PHP: 3 Ways to Get City/Country from IP Address
  • PHP: How to find the mode(s) of an array (4 examples)
  • PHP: Calculate standard deviation & variance of an array