What is a service class in PHP?

When you hear the term service in relation to PHP it can lead to some ambiguity. Like the previous post where we referred to repositories, the term services has several connotations in the world of programming. For example, you have a Service running on your computer like Nginx, or in Windows you also have services and a manager for those. Perhaps in the context of an application you have a web service that exposes some data to a client. The list goes on and on, so what then is a service class?

As much as I hear this term used in relation to Laravel, it's sad to say that this is not something that is readliy explained anywhere that i've found in the community and so I turned to the next best place. Since Laravel is built a lot on components that come from symfony I found this definition on the symfony site and I ran with it:

Put simply, a Service is any PHP object that performs some sort of "global" task.

The article goes on to say that services are generic classes that are built to perform a specific task. For instance, on might have a mailer service or a user creation service. These are tasks that need to be repeated over and over in various places and thus don't fit into any one place that well in particular. That makes them good candidates to become a service. Let's dig deeper with another definition.

This definition from Stack Overflow is particularly useful. The context it refers to is Java but it explains the concept super clear. In this post a SO user says:

When code doesn't naturally fit into one class or another nicely then you have a candidate for a service.

Concepts are nice but give us an example!

Ok ok, so let's say you're building a dashboard app. It pulls data from quizzes that users take. Then it displays them in a secured dashboard. Right off the bat we see we need to have registration, user creation, data management, ect.

You could just make the user registration code live in you user model, but what happens if you need to register a user somewhere else though? Let's look at the two different approaches.

//User.php
...
public function store()  
{
    $user  = array();
    $user['username']     = Input::get('username');
    $input['email']     = Input::get('email');
    $input['password']     = Input::get('password');
    $input['password_confirm'] = Input::get('password_confirm');

    User::create($user);
}

This method assumes you're doing validation

So what's the matter witch this approach. Well technically nothing. It works. All of this logic now is tied to one spot inside your store method of your User model. It seems like this is an anwful lot of knowldge that the store method doesn't need to know, a lot of knowledge that seems better placed elsewhere. Let's look at an alternate approach.

After all, why should a core feature of your app only be able to be used in one instance, imprisoned inside one method, and inflexible?

Service(s) with a smile :)

What would be a more flexible way? Well let's explore. You could:

  1. Pass an instance of a UserRegistrationServiceInterface through your constructor to your user model and assign it to a property in the User model.

  2. Then bind an implementation somewhere else.

This style would allow you to have different implementations of services, a standard user vs a admin user for example. You can repeat this code cleanly and concisely anywhere you need registration to take place, your code is tightly coupled and highly cohesive, and best of all it's easy to adapt / maintain.

So how would our User.php store method look after this?

...
public function __construct( UserRegistrationServiceInterface $registrar )  
{
    $this->registrar = $registrar;
}
public function store()  
{
    $this->registrar->register(Input::all());
}

Summary

In short, a service class is code that you construct to perform a global task. It doesn't fit natrually into another class do to knowledge / responsibility or other reasons. Examples of services / service like component in Laravel may be the Cache mechanism, The logging component, The IoC container itself, or most vendor loaded items for that matter.

I hope this made services a little clearer. Im still gettting my feet with them myself and since I didn't find much info about them readily availible I hope that this helps some of you.