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');
}
}
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'));
}
}
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');
}
}
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;
// ...
}
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);
}
}
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 :)
Top comments (2)
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?
I think it's very clear. You should try reading the article again.