What is the open-closed principle (in PHP)

In general, the open-closed principle is a software engineering principle that states that modules should be open for extension but closed for change. That might sound like a contradiction, but looking through examples will make the difference between extension and change, clear.

For PHP, or any other language, the open-closed principle can be applied at many different levels (module, class, function, etc). For example, we can say that a PHP class is closed for change but open for extension or we might say that a PHP function does not conform to this principle and is thus open for change (keep in mind that some code has to be open for change).

What problem does the open-closed principle solve?

Imagine a system in which a single change has multiple consequences. You update a method in a class which is called from many other classes and in turn many more. That single update had a cascading effect. The objective of OCP is to minimize or completely remove the cascading of effects.

If our update doesn't affect other classes, we can be confident that our new functionality doesn't have any unintended side effects.

A PHP example of the open-closed principle: Rendering a contact Form

Suppose we want to build a contact form on our website, we'd like to collect a name and email address. Our first (very simple) ContactForm class might look like the code below:

The render method echo's out the form elements that we need. But how do we update the render method in the future, when we might want to also collect a telephone number? In it's current form, the render method is actually open for change, which is not what we want. It should be open for extension but closed for change.

OCP in CakePHP

Let's look at a real world example of OCP, in CakePHP, we'll look at the controls method:

CakePHP uses the controls method to return the completed form inputs, similar to our render method.

It differs from our code in the following respects:
  1. It is passed the fields parameter.
  2. It loops through each element, without any limitation to the number of elements.
  3. It returns the completed output string.

You can call the controls method as shown below:

The controls method is passed an array of form elements to generate.

Updating our PHP code to comply with the open-closed principle

We'll first clean up our code a little before adding function parameters and a loop for our elements.

We've now prepared our code to make it easier for us to comply with the open-closed principle.

Our render method can now accept an arbitrary number of input elements and render them out. But what happens if we pass a type 'unknown' to it, will that render valid HTML?

We need to update FormInput to check for valid types.

We can be confident our render method only returns valid HTML and it is consistent with the open-closed principle. Is the FormInput class itself open for extension and closed for change?

How do we add new validTypes, like a password or telephone number?
The below are two possible solutions:
  1. Declare validTypes in a configuration table in a separate file.
  2. Declare validTypes in a different static class.

Key Takeaways

  • Implementing the open-closed principle will give you the confidence to make updates knowing that there aren't any cascading effects because of your changes.
  • We've seen an example of the open-closed principle in CakePHP and how we go about implementing it ourselves.
  • The open-closed principle in PHP can be applied at the class and function level, have you applied the same principle at any other level?

Further Reading

This article is part of a series on SOLID in PHP, the next article is The Liskov Substitution Principle, the previous article is The Single Responsibility Principle.