PHP Proxy Design Pattern Structural Pattern

PHP Proxy Pattern

A short screencast: the Proxy pattern — a surrogate object that controls access to the real one. We will build lazy image loading: the heavy object is created on first access and cached afterwards.

Proxy Pattern — open the lesson page

Overview

A Proxy is an object with the same interface as the real subject. It intercepts calls and decides when and how to pass them to the original. A common case is lazy loading: ImageProxy does not create RealImage until display() is called. On the next call the real object is already cached, so it is not "loaded" again. The client works through the shared Image interface and never knows it is talking to a proxy.

UML diagram

classDiagram class Image { <<interface>> +display() string } class RealImage { -string file +display() string } class ImageProxy { -string file -RealImage real +display() string } Image <|-- RealImage : implements Image <|-- ImageProxy : implements ImageProxy o-- RealImage : lazily creates

Code

Image.php

interface Image
{
    public function display(): string;
}

RealImage.php

class RealImage implements Image
{
    public function __construct(private string $file)
    {
        echo 'loading: '.$this->file.PHP_EOL;
    }

    public function display(): string
    {
        return 'displaying: '.$this->file;
    }
}

ImageProxy.php

class ImageProxy implements Image
{
    private ?RealImage $real = null;

    public function __construct(private string $file) {}

    public function display(): string
    {
        if ($this->real === null) {
            $this->real = new RealImage($this->file);
        }

        return $this->real->display();
    }
}

demo.php

require_once 'Image.php';
require_once 'RealImage.php';
require_once 'ImageProxy.php';

$image = new ImageProxy('photo.jpg');

echo $image->display().PHP_EOL;
echo $image->display().PHP_EOL;

Example output

display() is called twice, but the "loading" happens exactly once — the proxy creates the real object on first access and caches it:

loading: photo.jpg
displaying: photo.jpg
displaying: photo.jpg

Advantages

  • Controls access to the real object without changing the client.
  • Lazy initialisation: the heavy object is created on first access.
  • Lets you add caching, logging or access checks.
  • The client uses the same interface and notices nothing.

When to use

  • When a heavy object should be loaded lazily.
  • When access control or permission checks are needed.
  • When calls should be cached or logged.
  • When the real object is remote or expensive to create.

Usage in Laravel

In Laravel the proxy is the facade: Illuminate\Support\Facades\Facade forwards a static call to the real object from the container. Eloquent's deferred relation loading (Illuminate\Database\Eloquent\Relations\...) also acts as a proxy: accessing $post->comments issues the database query only at the moment of access.