In this PHP article, we will be discussing the single responsibility principle as it applies to PHP classes and objects, we'll also look at PHP examples of the single responsibility principle (SRP).
We will consider the single responsibility principle in limited terms (of PHP), for an in-depth look at the single responsibility principle, you can read uncle Bob's article on SRP.
What is the Single Responsibility Principle?
Now that we know a little more about SRP, we can think about what causes a class to change. From a PHP perspective, the most likely change is probably a change in business rules. There might be other reasons for low level languages, like hardware changes, but for the most part, we'll think of change in PHP as a change in business requirements.
With that in mind, we can rephrase the single responsibility principle as:
The single reason for change principle.
In other words: our classes should have only one reason for change (if we implement the single responsibility principle on them)
SRP example in PHP: Render an HTML input element
Let's look at an example of a PHP class which we use to render an HTML input. Our class in called
HTMLInput which has a method
render to return an HTML input element.
HTMLInput class is simple enough, but what if we wanted to add attributes to our input, we could update our
render method to accept an associative array
HTMLInput class now renders an input element with attributes, but does it have more than one reason for change? What if the attributes array has a style key which we use to render inline styles?
HTMLInput class would have two possible reasons for change:
- The way in which an input element is rendered.
- And the way in which attributes are generated.
So how do we update our
HTMLInput class to have one reason for change only i.e to conform with the single responsibility principle?
Let's look at an example of the single responsibility principle in Yii framework, you can learn more about Yii PHP framework here.
The Yii framework has an
InputWidget class similar to our
HTMLInput class, and a corresponding
BaseHtml class provides a set of static methods for generating commonly used HTML tags. The
InputWidget class uses the
renderInputHtml method to render it's attributes.
InputWidget class is not responsibile for generating the tag attributes.
SRP in Laminas's MVC layer (Zend Framework): The FormLabel
Let's look at another SRP example, this time using the
FormLabel class as an example, you can learn more about Laminas MVC here.
FormLabel class has an
openTag method to generate an opening label tag, which uses the
createAttributesString method to generate the tag attributes.
AbstractHelper class in Laminas provides base functionality for all form view helpers, which implements the
createAttributesString method. In Laminas's MVC layer, the
FormLabel class does not take responsibility for the tag attributes.
It outsources that responsibility to the
HTMLInput class conformed to SRP, we'd have to refactor our code to outsource the attribute generation method to a separate class.
Our examples shown clearly separate responsibilities between classes, though not obvious when you start thinking about your classes, grouping responsibilities together may become easier with experience.
In general, implementing the single responsibility principle in PHP would depend on your business rules, with emphasis on the possible causes for change in your classes and the likelihood of those changes actually occurring.
The key ingredient for the single responsibility principle would be deciding how to group responsibilities, how do you think about separating responsibilities when designing your classes?
This article is part of a series on SOLID in PHP, the follow up to this article is The Open-Closed Principle.