Prototype Pattern

The Prototype Pattern is a creational design pattern used to create new objects by copying existing objects instead of building them from scratch. This article explains how Prototype works, when to use it, and how to implement it in PHP with cloning examples.

Jun 10, 2026
Prototype Pattern

Prototype Pattern

The Prototype Pattern is a creational design pattern used to create new objects by copying existing objects instead of creating them from scratch. It is useful when object creation is expensive, complex, or when many similar objects are needed with small differences.

In Object-Oriented Programming, the Prototype Pattern allows an object to act as a template for creating other objects. Instead of asking a factory or constructor to build a new object step by step, the application clones an existing object and then modifies only the parts that need to change.

Introduction

In previous articles of this Design Patterns series, we discussed the Factory Pattern, Abstract Factory Pattern, and Builder Pattern. These are all creational design patterns, but each one solves a different object creation problem.

The Factory Pattern decides which object should be created. The Abstract Factory Pattern creates families of related objects. The Builder Pattern constructs complex objects step by step. The Prototype Pattern creates new objects by copying an existing object.

This pattern is especially useful when object initialization requires many values, database data, configuration, API responses, or expensive setup logic. By cloning a ready object, the application can avoid repeating the same construction process many times.

What Is the Prototype Pattern?

The Prototype Pattern is a design pattern that creates objects by cloning an existing object, called the prototype. The cloned object becomes a new instance with the same initial state as the original object.

In simple terms, the prototype is a ready-made sample. When the application needs a similar object, it copies the sample and customizes the copy.

For example, a document editor may use a prototype invoice template. When a new invoice is needed, the system clones the invoice template and changes customer details, invoice number, and dates.

Main Idea of Prototype Pattern

The main idea of the Prototype Pattern is based on copying instead of constructing. This can be helpful when creating a new object from zero requires repeated setup steps.

The pattern usually includes:

  • A prototype object that already contains default values or prepared configuration.

  • A cloning mechanism to create a copy of the object.

  • Optional customization of the cloned object after it is created.

This approach can make object creation faster, simpler, and more consistent in specific situations.

Why the Prototype Pattern Is Important

The Prototype Pattern is important because object creation can sometimes be expensive or repetitive. Some objects require complex setup, many constructor parameters, nested objects, or default configurations.

If the same setup is repeated many times, the code becomes harder to maintain. Prototype Pattern allows developers to prepare an object once and reuse it as a template.

This can improve performance in some cases and improve code organization when many objects share the same base structure.

Problem Without Prototype Pattern

Imagine an application that creates report templates. Each report has a title, layout, sections, metadata, filters, style settings, and export options. Creating each report from scratch may require many repeated steps.

$report = new Report();
$report->setLayout('professional');
$report->setFont('Arial');
$report->setPageSize('A4');
$report->addSection('Summary');
$report->addSection('Details');
$report->enableCharts();
$report->setExportFormat('pdf');

If many reports use the same base configuration, repeating these steps in multiple places is not clean. With Prototype Pattern, the application can create one prepared report object and clone it whenever a similar report is needed.

Prototype Pattern and Cloning

Cloning is the process of creating a copy of an object. In PHP, objects can be cloned using the clone keyword.

$copy = clone $original;

The copied object is a new instance, but it initially contains the same property values as the original object.

However, developers must understand the difference between shallow copy and deep copy. This is very important when objects contain other objects inside them.

Basic Prototype Example in PHP

The following example shows a simple Prototype Pattern implementation in PHP:

class ReportTemplate
{
    public string $title;
    public string $layout;
    public array $sections = [];

    public function __construct(string $title, string $layout)
    {
        $this->title = $title;
        $this->layout = $layout;
    }

    public function addSection(string $section): void
    {
        $this->sections[] = $section;
    }
}

$defaultReport = new ReportTemplate('Default Report', 'professional');
$defaultReport->addSection('Summary');
$defaultReport->addSection('Details');

$monthlyReport = clone $defaultReport;
$monthlyReport->title = 'Monthly Sales Report';

In this example, the default report acts as the prototype. The monthly report is created by cloning the default report and changing the title.

Using __clone in PHP

PHP provides a special magic method called __clone. This method is automatically called after an object is cloned. Developers can use it to reset values, copy nested objects, or prepare the cloned object.

class Document
{
    public string $title;
    public string $documentId;

    public function __construct(string $title)
    {
        $this->title = $title;
        $this->documentId = uniqid('doc_', true);
    }

    public function __clone()
    {
        $this->documentId = uniqid('doc_', true);
    }
}

$original = new Document('Invoice Template');
$copy = clone $original;

echo $original->documentId;
echo $copy->documentId;

In this example, the cloned document receives a new document ID. This prevents the original and cloned documents from sharing the same identifier.

Shallow Copy

A shallow copy means that the object itself is copied, but nested objects inside it are still shared by reference. This can create unexpected behavior if the cloned object changes a nested object.

For example, if a Report object contains a Style object, cloning the report may copy the report object but still reference the same Style object. If the cloned report changes the style, the original report may be affected too.

This is why developers must be careful when cloning objects that contain other objects.

Shallow Copy Example in PHP

class Style
{
    public string $font = 'Arial';
}

class Report
{
    public Style $style;

    public function __construct()
    {
        $this->style = new Style();
    }
}

$reportA = new Report();
$reportB = clone $reportA;

$reportB->style->font = 'Calibri';

echo $reportA->style->font;

In this example, changing the font through reportB may also affect reportA because both reports can share the same Style object after a shallow clone.

Deep Copy

A deep copy means that the object and its nested objects are copied. This prevents the original object and the cloned object from sharing internal objects by reference.

In PHP, deep copy can be handled manually inside the __clone method by cloning nested objects.

Deep Copy Example in PHP

class Style
{
    public string $font = 'Arial';
}

class Report
{
    public Style $style;

    public function __construct()
    {
        $this->style = new Style();
    }

    public function __clone()
    {
        $this->style = clone $this->style;
    }
}

$reportA = new Report();
$reportB = clone $reportA;

$reportB->style->font = 'Calibri';

echo $reportA->style->font;

In this example, reportB receives its own copy of the Style object. Changing the cloned report style does not affect the original report style.

Prototype Interface

Some implementations define a prototype interface with a clone method. This makes the pattern explicit and allows different prototype classes to follow the same contract.

interface Prototype
{
    public function clone(): Prototype;
}

class InvoiceTemplate implements Prototype
{
    public function __construct(
        public string $title,
        public array $items = []
    ) {
    }

    public function clone(): Prototype
    {
        return clone $this;
    }
}

This structure can be useful when the application works with different prototype objects through a common interface.

Real-World Example: Invoice Template

Invoices are a practical example of the Prototype Pattern. Many invoices may share the same structure, tax rules, footer text, currency, and layout. Instead of building the invoice from scratch every time, the system can clone a predefined invoice template.

class Invoice
{
    public string $invoiceNumber;
    public string $customerName;
    public string $currency = 'USD';
    public array $items = [];
    public string $footer = 'Thank you for your business.';

    public function __construct()
    {
        $this->invoiceNumber = uniqid('INV-', true);
    }

    public function __clone()
    {
        $this->invoiceNumber = uniqid('INV-', true);
        $this->items = [];
        $this->customerName = '';
    }

    public function addItem(string $name, float $price): void
    {
        $this->items[] = [
            'name' => $name,
            'price' => $price,
        ];
    }
}

$template = new Invoice();

$invoice = clone $template;
$invoice->customerName = 'John Doe';
$invoice->addItem('Web Development Service', 500);

In this example, the invoice template provides default currency and footer values. The cloned invoice receives a new invoice number and can be customized for a specific customer.

Real-World Example: Game Objects

The Prototype Pattern is common in game development. A game may need to create many similar enemies, weapons, items, or characters. Instead of configuring each object from scratch, the game can clone prepared prototypes.

For example, a game can define a prototype for a basic enemy with default health, speed, damage, and appearance. When the game needs more enemies, it clones the prototype and changes small values such as position or level.

This makes object creation more efficient and easier to manage.

Real-World Example: Document Templates

Document systems often use templates for contracts, reports, invoices, certificates, and letters. Prototype Pattern fits this case naturally because a template can be cloned and customized.

For example, a certificate template may include default layout, logo, title, signature area, and style. The system clones the template and updates the recipient name, date, and certificate number.

This avoids repeating template configuration and ensures consistency across generated documents.

Prototype Pattern vs Factory Pattern

The Prototype Pattern and Factory Pattern are both creational design patterns, but they create objects differently.

The Factory Pattern creates objects by choosing and instantiating a class. It usually uses constructors and may decide the class based on input or configuration.

The Prototype Pattern creates objects by copying an existing object. It is useful when the object already has a prepared state that should be reused.

In short, Factory asks “which class should I create?” while Prototype asks “which existing object should I copy?”

Prototype Pattern vs Builder Pattern

The Builder Pattern creates complex objects step by step. The Prototype Pattern creates objects by copying an already prepared object.

Use Builder when the construction process needs to be readable and controlled step by step. Use Prototype when a ready object can be used as a template and copied efficiently.

For example, an EmailMessageBuilder is useful when constructing an email with many optional fields. An Invoice prototype is useful when many invoices share the same default structure.

Prototype Pattern vs Singleton Pattern

The Singleton Pattern ensures that only one instance of a class exists. The Prototype Pattern creates many new instances by copying an existing object.

These patterns solve opposite problems. Singleton limits object creation, while Prototype makes it easier to create multiple similar objects.

Understanding this difference helps developers choose the correct pattern for the object creation problem they are facing.

When to Use Prototype Pattern

Use the Prototype Pattern when creating an object from scratch is expensive, repetitive, or complex, and when copying an existing object is easier.

Prototype Pattern is useful when:

  • Many similar objects are needed.

  • Object initialization is expensive or complex.

  • Objects have many default values.

  • Templates or presets are used.

  • The application needs to avoid repeated setup logic.

  • Runtime object configuration should be copied.

  • The exact object class may not be known by the client code.

If these conditions exist, Prototype Pattern can make object creation cleaner and more efficient.

When Not to Use Prototype Pattern

Do not use Prototype Pattern when object creation is simple and direct. If an object has only a few values and no expensive setup, using a constructor or factory may be clearer.

Avoid Prototype Pattern when:

  • The object is simple to create.

  • Cloning creates confusion or hidden shared references.

  • The object contains resources that should not be copied directly.

  • Deep copying is too complex to manage safely.

  • A builder or factory would express the intent more clearly.

Prototype should solve a real problem. It should not be added only because cloning is possible.

Benefits of Prototype Pattern

The Prototype Pattern provides several benefits in object-oriented software design.

Main benefits include:

  • Creates new objects by copying existing prepared objects.

  • Reduces repeated initialization logic.

  • Can improve performance when setup is expensive.

  • Supports template-based object creation.

  • Makes it easy to create many similar objects.

  • Can reduce dependency on concrete classes.

  • Works well for documents, templates, reports, and game objects.

These benefits make Prototype Pattern valuable when objects share a common starting state.

Drawbacks of Prototype Pattern

The main drawback of Prototype Pattern is that cloning can be tricky. If objects contain nested objects, shallow copying may cause the original and clone to share internal references.

Another drawback is that cloning objects with external resources can be dangerous. For example, objects that contain database connections, file handles, sockets, or external service clients should not always be cloned directly.

Prototype Pattern can also make code less obvious if developers are not familiar with cloning behavior. Clear documentation and careful implementation are important.

Prototype Pattern and Clean Code

The Prototype Pattern supports clean code when it removes repeated setup logic and makes object creation easier to understand. Instead of repeating many configuration steps, the application can clone a prepared prototype.

However, clean code also requires clarity. If cloning hides too much behavior or creates unexpected shared state, the design becomes harder to maintain.

Good Prototype usage should make object creation simpler, not more mysterious.

Prototype Pattern in Laravel

In Laravel applications, Prototype Pattern may be useful when working with templates, configuration objects, report objects, DTOs, document generation, or reusable export settings.

For example, a reporting module may keep a default report configuration object. When a user requests a custom report, the system clones the default configuration and changes filters, date ranges, and export options.

Laravel also provides factories for model creation, which are different from the Prototype Pattern, but both can be used for object creation depending on the problem.

Prototype Pattern in Symfony

In Symfony projects, Prototype Pattern can be used for complex message objects, command templates, report templates, form configuration objects, or document templates.

Symfony services are usually managed by the dependency injection container, so developers should be careful when cloning service objects. Prototype Pattern is often better suited for data objects, templates, and configuration objects rather than container-managed services with external dependencies.

Common Mistakes with Prototype Pattern

One common mistake is ignoring the difference between shallow copy and deep copy. This can cause cloned objects to share nested objects unexpectedly.

Another mistake is cloning objects that contain external resources such as database connections or open files. These resources may not behave correctly when copied.

A third mistake is using Prototype Pattern when a simple constructor would be clearer. If object creation is not complex, cloning may add unnecessary confusion.

A fourth mistake is not resetting unique values in cloned objects. For example, cloned invoices, documents, or orders should usually receive new IDs or numbers.

Best Practices for Prototype Pattern

To use Prototype Pattern correctly, developers should control cloning behavior carefully.

Useful best practices include:

  • Use Prototype when objects have expensive or repeated setup.

  • Use __clone to reset unique values such as IDs.

  • Clone nested objects when deep copy is required.

  • Avoid cloning external resources directly.

  • Document which parts of the object are copied and reset.

  • Use prototypes for templates, presets, and reusable configurations.

  • Keep cloned objects independent when changes should not affect the original.

  • Do not use Prototype when a constructor, factory, or builder is clearer.

These practices help prevent cloning-related bugs and keep the design understandable.

Practical Checklist Before Using Prototype Pattern

Before using Prototype Pattern, developers can ask these questions:

  • Is object creation expensive or repetitive?

  • Do many objects share the same default state?

  • Can a prepared object be safely copied?

  • Does the object contain nested objects that need deep copying?

  • Are there unique fields that must be reset after cloning?

  • Does the object contain resources that should not be cloned?

  • Would Factory or Builder be clearer for this problem?

If cloning a prepared object makes the code cleaner and safer, Prototype Pattern may be a good choice.

Conclusion

The Prototype Pattern is a creational design pattern that creates new objects by copying existing objects. It is useful when object creation is complex, expensive, or repetitive, and when many objects share the same default structure.

In PHP, Prototype Pattern is commonly implemented using the clone keyword and the __clone magic method. Developers must understand shallow copy, deep copy, and how to reset unique values to avoid unexpected behavior.

Prototype Pattern is useful for templates, reports, invoices, document generation, game objects, configuration objects, and reusable presets. However, it should be used carefully when objects contain nested objects or external resources. When applied correctly, Prototype Pattern can make object creation faster, cleaner, and more maintainable in object-oriented software projects.