Explore the Proxy Pattern in PHP, its intent, implementation, and use cases. Learn how to create proxy classes to control access to real subjects, including types like virtual, remote, protective, and smart references.
The Proxy Pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. This pattern is particularly useful in scenarios where direct access to an object is either costly or undesirable. By using a proxy, you can introduce additional functionality such as lazy initialization, access control, logging, or even remote access to an object.
The primary intent of the Proxy Pattern is to control access to an object. This can be achieved by creating a proxy class that acts as an intermediary between the client and the real subject. The proxy class can perform additional operations before or after forwarding the request to the real subject.
Let’s explore how to implement the Proxy Pattern in PHP by creating a proxy class that controls access to a real subject. We’ll use a simple example of a Book class and a BookProxy class.
First, define an interface that both the real subject and the proxy will implement. This ensures that the proxy can be used interchangeably with the real subject.
1<?php
2
3interface BookInterface {
4 public function getTitle(): string;
5 public function getAuthor(): string;
6}
Next, implement the real subject class that performs the actual operations.
1<?php
2
3class RealBook implements BookInterface {
4 private $title;
5 private $author;
6
7 public function __construct(string $title, string $author) {
8 $this->title = $title;
9 $this->author = $author;
10 }
11
12 public function getTitle(): string {
13 return $this->title;
14 }
15
16 public function getAuthor(): string {
17 return $this->author;
18 }
19}
Now, implement the proxy class that controls access to the real subject. In this example, the proxy will perform lazy initialization of the RealBook object.
1<?php
2
3class BookProxy implements BookInterface {
4 private $realBook;
5 private $title;
6 private $author;
7
8 public function __construct(string $title, string $author) {
9 $this->title = $title;
10 $this->author = $author;
11 }
12
13 private function initializeRealBook() {
14 if ($this->realBook === null) {
15 $this->realBook = new RealBook($this->title, $this->author);
16 }
17 }
18
19 public function getTitle(): string {
20 $this->initializeRealBook();
21 return $this->realBook->getTitle();
22 }
23
24 public function getAuthor(): string {
25 $this->initializeRealBook();
26 return $this->realBook->getAuthor();
27 }
28}
Finally, use the proxy in your client code. The client interacts with the proxy as if it were the real subject.
1<?php
2
3$bookProxy = new BookProxy("Design Patterns", "Erich Gamma");
4echo "Title: " . $bookProxy->getTitle() . "\n";
5echo "Author: " . $bookProxy->getAuthor() . "\n";
To better understand the Proxy Pattern, let’s visualize the interaction between the client, proxy, and real subject using a sequence diagram.
sequenceDiagram
participant Client
participant Proxy
participant RealSubject
Client->>Proxy: Request (e.g., getTitle())
Proxy->>Proxy: Check if RealSubject is initialized
alt RealSubject not initialized
Proxy->>RealSubject: Initialize RealSubject
end
Proxy->>RealSubject: Forward request
RealSubject-->>Proxy: Return result
Proxy-->>Client: Return result
The Proxy Pattern is versatile and can be applied in various scenarios. Here are some common use cases:
Let’s extend our previous example to include logging functionality using a smart reference proxy.
1<?php
2
3class LoggingBookProxy implements BookInterface {
4 private $realBook;
5 private $title;
6 private $author;
7
8 public function __construct(string $title, string $author) {
9 $this->title = $title;
10 $this->author = $author;
11 }
12
13 private function initializeRealBook() {
14 if ($this->realBook === null) {
15 $this->realBook = new RealBook($this->title, $this->author);
16 }
17 }
18
19 public function getTitle(): string {
20 $this->initializeRealBook();
21 $this->logAccess("getTitle");
22 return $this->realBook->getTitle();
23 }
24
25 public function getAuthor(): string {
26 $this->initializeRealBook();
27 $this->logAccess("getAuthor");
28 return $this->realBook->getAuthor();
29 }
30
31 private function logAccess(string $method) {
32 echo "Logging access to method: $method\n";
33 }
34}
When implementing the Proxy Pattern, consider the following:
PHP offers several features that can enhance the implementation of the Proxy Pattern:
__get, __set, __call) to intercept and handle method calls dynamically.The Proxy Pattern is often confused with other patterns such as the Decorator and Adapter patterns. Here are some distinctions:
To deepen your understanding of the Proxy Pattern, try modifying the code examples:
Remember, mastering design patterns is a journey. As you experiment with the Proxy Pattern, you’ll gain insights into how to control access to objects effectively. Keep exploring, stay curious, and enjoy the process of becoming a more skilled PHP developer!