DEV Community

Cover image for The Difference Between Service Classes and Traits in PHP
Andrew Savetchuk
Andrew Savetchuk

Posted on • Updated on • Originally published at blog.savetchuk.com

The Difference Between Service Classes and Traits in PHP

The main difference between service classes and traits is that service classes provide a complete implementation of a specific service or functionality, whereas traits provide a set of methods that can be mixed into multiple classes to provide them with additional functionality.

Both service classes and traits can be reused throughout an application and service classes can utilize traits.

Service Classes​

We can think of a service class like a PHP object that performs some sort of a "global" task. Service classes are often used to encapsulate complex business logic or to provide a unified interface to interact with external services, such as databases or web services.

For example, there may be a mailing service or a user creation service. These are tasks that need to be repeated over and over again in different places. This makes them good candidates for a service class.

Some ideas for service classes:

  • Service class responsible for sending SMS via Twilio.

  • Service class responsible for sending Emails via Mailgun (Newsletter Service).

  • Service class responsible for working with UptimeRobot APIs.

  • Service class responsible for storing and deleting images on the cloud.

Example of a Service Class in Laravel​

Here is an example of the App\Services\UptimeRobotAPI.php service class that is responsible for connecting to the UptimeRobot API and retrieving data:

<?php

namespace App\Services;

use GuzzleHttp\Client;

class UptimeRobotAPI
{
  protected string $url;
  protected string $http;
  protected array $headers;

  public function __construct(Client $client)
  {
    $this->url = 'https://api.uptimerobot.com/v2/';
    $this->http = $client;
    $this->headers = [
      'cache-control' => 'no-cache',
      'content-type'  => 'application/x-www-form-urlencoded',
    ];
  }

  private function getResponse(string $path)
  {
    // Making a GET request to UptimeRobot API using GuzzleHttp...
  }

  private function postResponse(string $path, array $params = [])
  {
    // Making a POST request to UptimeRobot API using GuzzleHttp...
  }

  public function getMonitors()
  {
    return $this->getResponse('getMonitors');
  }
}
Enter fullscreen mode Exit fullscreen mode

The UptimeRobotAPI service is now can be used like so:

<?php

namespace App\Http\Controllers;

use App\Services\UptimeRobotAPI;

class MonitorsController extends Controller
{
  public function index(UptimeRobotAPI $uptimeRobotAPI)
  {
    $monitors = $uptimeRobotAPI->getMonitors();

    return view('monitors.index', compact('monitors'));
  }
}
Enter fullscreen mode Exit fullscreen mode

More Service Class Examples

Another example of a service class would be a PaymentService or StripeService - a service class that encapsulates payment-related functionality, such as processing payments, managing payment methods, and handling refunds.


Traits

In PHP, a class can only inherit from a single parent class, which can limit the ability to reuse code. Traits were introduced to solve this problem by providing a way to reuse code across multiple classes without using inheritance. They allow developers to define a set of methods that can be shared among multiple classes, allowing for more flexible and modular code. Traits are particularly useful when building complex applications that require a lot of code reuse.

Example of a Trait in Laravel

Here is an example of the app/Traits/ApiResponder.php trait I often use when developing Laravel applications:

<?php

namespace App\Traits;

use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

trait ApiResponder
{
  public function successResponse($data, int $code = Response::HTTP_OK): JsonResponse {
    return response()->json([
      'data' => $data,
      'code' => $code,
    ], $code)->header('Content-Type', 'application/json');
  }

  public function errorResponse($error, int $code): JsonResponse
  {
    return response()->json([
      'error' => $error,
      'code'  => $code,
    ], $code)->header('Content-Type', 'application/json');
  }
}
Enter fullscreen mode Exit fullscreen mode

Once the trait is created, you can import it as follows:

<?php

namespace App\Http\Controllers;

use App\Traits\ApiResponder;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;

class Controller extends BaseController
{
  use AuthorizesRequests, DispatchesJobs, ValidatesRequests, ApiResponder;

  // ...
}
Enter fullscreen mode Exit fullscreen mode

Once the trait is imported it is ready to use:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\JsonResponse;

class TwilioSettingsController extends Controller
{
  public function fetchSettings(): JsonResponse
  {
    $response = TwilioSettings::getSettings();

    return $this->successResponse($response);
  }
}
Enter fullscreen mode Exit fullscreen mode

More Trait Examples

Another example of a trait would be a LoggableTrait - a trait that adds logging functionality to a class, allowing it to log messages to a log file or other logging system. This trait can be used by multiple PHP classes, including Service Classes.


The end, I hope this information was helpful, stay tuned for more content :)

Latest comments (2)

Collapse
 
aleksandryask profile image
Aleksandr

By the title, I was hoping you would tell me the fundamental difference. I did not see an explanation of why when we should use traits. Why should I not use ApiResponseService with the same methods. And doesn't using traits like this lead to the same problems that multiple inheritance has?

Collapse
 
logicsatinn profile image
Calvin Jackson

I think it's very clear. You should try reading the article again.