An introduction to WeakMap in PHP (6 examples)

Updated: February 20, 2024 By: Guest Contributor Post a comment

Introduction

PHP introduced WeakMap in version 8.0, making a significant move towards more efficient memory management for applications. A WeakMap allows us to associate values to objects in a way that doesn’t prevent those objects from being garbage collected if they are no longer in use elsewhere. This feature is particularly useful when designing large, complex applications that require efficient memory usage and performance.

In this tutorial, we will explore WeakMap through 6 practical examples, ranging from basic usage to more advanced scenarios. Let’s begin by understanding its syntax and why it’s a game changer for certain PHP applications.

Example 1: Basic Usage of WeakMap

$weakMap = new WeakMap();
$object1 = new stdClass();
$object2 = new stdClass();

// Associating values with objects
$weakMap[$object1] = 'Data for object1';
$weakMap[$object2] = 'Data for object2';

// Show stored data
var_dump($weakMap[$object1], $weakMap[$object2]);

Output: string(15) “Data for object1” string(15) “Data for object2”

This example demonstrates the most straightforward application of WeakMap: using it to associate arbitrary data with object instances. This is particularly beneficial because it doesn’t affect the garbage collection process, allowing the objects to be reclaimed when not needed, reducing overall memory consumption.

Example 2: Automatic Removal upon Object Destruction

$weakMap = new WeakMap();
$object = new stdClass();
$weakMap[$object] = 'Example data';

// Destroying the object
unset($object);

// Trying to access the data
var_dump(isset($weakMap[$object]));

Output: bool(false)

This example illustrates how WeakMap interacts with PHP’s garbage collection: when the associated object is no longer referenced, the entry in the WeakMap is automatically removed. This behavior is critical for applications that manage a large volume of objects and need to free memory efficiently.

Example 3: Combining WeakMap with Object Classes

class User {}

$user1 = new User();
$user2 = new User();

$weakMap = new WeakMap();
$weakMap[$user1] = ['username' => 'john_doe', 'email' => '[email protected]'];
$weakMap[$user2] = ['username' => 'jane_doe', 'email' => '[email protected]'];

foreach ($weakMap as $user => $data) {
  echo $user->username . ': ' . $data['email'] . "\n";
}

This example demonstrates how WeakMap can be applied to objects of user-defined classes. It shows the ability to store and retrieve complex data associated with specific instances of a class, without preventing those instances from being garbage collected. Note: The code snippet above contains an intended conceptual representation and would need adjustments to correctly access object properties.

Example 4: Using WeakMap in Dependency Injection

One of the more advanced applications of WeakMap is in the realm of dependency injection. Here we will see how we can use WeakMap to associate dependencies with object instances without affecting their life cycle.

class DatabaseConnection {}

class UserRepository {
  private $connection;

  public function __construct(DatabaseConnection $connection) {
    $this->connection = $connection;
  }
}

$connection = new DatabaseConnection();
$usersRepository = new UserRepository($connection);

$weakMap = new WeakMap();
$weakMap[$usersRepository] = $connection;

// Now, UserRepository and DatabaseConnection instances are loosely coupled,
// thanks to WeakMap.

This example elegantly shows how WeakMap opens up new possibilities for managing dependencies in an application while maintaining optimal memory utilization.

Example 5: WeakMap for Caching

Caching with WeakMap can significantly improve the performance of applications, but it should be used wisely. Let’s explore a scenario where WeakMap is beneficial for caching object-related data without persisting beyond the object’s usefulness.

class Product {}

$product1 = new Product();
$product2 = new Product();

$weakMap = new WeakMap();
$weakMap[$product1] = 'Cached data for product1';
$weakMap[$product2] = 'Cached data for product2';

// Cached data is available as long as the product objects exist.

As illustrated, WeakMap offers a practical solution for caching by associating data to objects for the duration of their existence, without forcing them to remain in memory unnecessarily.

Example 6: Optimizing Memory Usage in Large Applications

Let’s simulate adding user sessions to WeakMap and demonstrate how it can efficiently manage memory by allowing user objects to be garbage collected when they are no longer referenced elsewhere in the application. We’ll also show how to access session data associated with user objects and how the WeakMap behaves when user objects are no longer accessible.

class User {
    public function __construct(public string $name) {}
}

class SessionData {
    public function __construct(public array $data) {}
}

// Creating a new WeakMap to hold user sessions
$weakMap = new WeakMap();

// Simulating adding user objects and their sessions
$user1 = new User('Alice');
$user2 = new User('Bob');

$weakMap[$user1] = new SessionData(['last_login_date' => '2023-02-14']);
$weakMap[$user2] = new SessionData(['last_login_date' => '2023-02-15']);

// Function to display session data for all users in the WeakMap
function displaySessions(WeakMap $weakMap): void {
    foreach ($weakMap as $user => $sessionData) {
        echo $user->name . "'s last login date: " . $sessionData->data['last_login_date'] . "\n";
    }
}

// Display current sessions
echo "Current sessions:\n";
displaySessions($weakMap);

// Unsetting $user1 to simulate the user object being out of scope/garbage collected
unset($user1);

// Garbage collection might not happen immediately, but let's try to force it for demonstration
gc_collect_cycles();

// Display sessions after $user1 is unset and potentially garbage collected
echo "\nSessions after unsetting \$user1:\n";
displaySessions($weakMap);

In this enhanced example:

  1. We define User and SessionData classes to simulate a real-world application scenario where user objects might be associated with session data.
  2. We add two user objects to the WeakMap with corresponding session data.
  3. We display the session data for all users to show that the WeakMap initially contains the sessions for both users.
  4. We unset one of the user objects ($user1) and attempt to force garbage collection. This simulates the scenario where a user object goes out of scope or is no longer needed.
  5. We display the session data again to demonstrate that the session for the unset user object is no longer in the WeakMap, showcasing how WeakMap allows associated data to be automatically cleaned up when the key objects are garbage collected.

This example illustrates the benefits of using WeakMap for managing temporary associations in applications where efficient memory use is critical, such as those managing a large number of user sessions.

Conclusion

The introduction of WeakMap in PHP 8.0 provides developers with a powerful tool for memory-efficient object management. Through these examples, we’ve seen how WeakMap can be effectively utilized in different scenarios, from basic to complex, highlighting its versatility and utility in optimizing applications for better performance and design.