Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

cloud4bpm's avatar

Use of SOLID principles for creating custom PHP Providers of Services Classes

Hi,

I'm creating some classes accessing certain APIs through PHP code, but I want my code to be clear and, if possible, SOLID. But I find the following questions:

For example, if I create a class that allows me access to an API and get data in various formats JSON, XML, CSV, etc. It would be best to create an abstract class and individual part of each provider is implemented through a child class. I'm using this aproximation right now.

Use public API interfaces for general Provider functionality.

Use traits for the common part (eg, methods that are implemented in the same way in each individual Provider).

But the problem comes when not all APIs (eg Authentication, Conversors, ...) might not have the same amount of common API methods. For example a new method, but which, by its nature, is not possible pull-up to the Abstract Provider class.

What strategy would you use if you have to target potential providers of certain APIs if not all meet the same interface but some methods implemented more than others? Extract the base methods on the Abstract Provider class and using Segregation Interfaces?

Thanks in advance.

0 likes
9 replies
cloud4bpm's avatar

Anybody can view this question? I cannot view in the discussions main panel but using My Questions menu item I view that and get the correct link, or if I answer my own question:

https://laracasts.com/discuss/channels/general-discussion/use-of-solid-principles-for-creating-custom-php-providers-of-services-classes

If I answer within the question I view in the main discussion panel, I tried clearing this second post and the question dissapears from the main discussions.

Maybe a cache issue?

Thanks.

martinbean's avatar

@cloud4bpm I’d say just start coding and re-factor as you go. Watch the Laracast lessons on the SOLID principles, and then see if any of them can be applied to your code.

You don’t say why types of APIs you’re working with, so I can’t really offer any suggestions on code organisation or which methods should be abstract or whatnot.

cloud4bpm's avatar

Hi @martinbean , many thanks for your answer.

I'm working with Currency Converters and I create a general Provider and I'm getting knowledge about some interesting available APIs.

But not all are using the same public functionality, that is why I'm asking about that.

I have not access to view the SOLID Series because I'm currently not a subscriber, but I'm evaluating for that, although I'm using those SOLID Patterns as I commented here.

Thanks again.

martinbean's avatar

@cloud4bpm Then think about the operations you’d want to perform against a currency converter and place those methods in an interface. Thinking about it, a currency converter only has one use: convert an amount in one currency to another. So you could have a convert() method that accepts three parameters: amount, currencyFrom, and currencyTo. Then have your individual classes implement that method:

interface CurrencyConverter
{
    public function convert($amount, $from, $to);
}
namespace App\CurrencyConverter;

use App\Contracts\CurrencyConverter as CurrencyConverterContract;
use GuzzleHttp\Client as HttpClient;

class OpenExchangeRate implements CurrencyConverterContract
{
    public function __construct(HttpClient $http, $clientId)
    {
        $this->http = $http;
        $this->clientId = $clientId;
        $this->baseUrl = 'https://openexchangerates.org/api';
    }

    public function convert($amount, $from, $to)
    {
        $response = $this->http->get($this->baseUrl.'/convert/'.$amount.'/'.$from.'/'.$to);

        return $response->json();
    }
}

Note: This was written off the cuff and isn’t meant to be working code. But should be enough to get you started.

cloud4bpm's avatar

Many thanks @martinbean for your sample but, in example if you see the following API CurrencyLayer you can find some other methods:

live()
historical()
...

Thinking about that methods is why I was thinking about using Segregation Interface (eg. HistoryInterface.php with getHistoricalData() method) and implement by the specific ConversionProvider).

Thanks again.

martinbean's avatar

@cloud4bpm Yes. Different APIs are going to have methods with different names and functionality. The idea of an interface is to allow your application code to access the functionality of these APIs through common method names without worrying about the underlying implementation.

So in your example, if one API offers historical data then you may define methods in an interface and apply that to the relevant wrapper classes. It’s perfectly acceptable to implement more than one interface. That way, you can tell what methods an API wrapper implements by checking what interfaces they implement:

if ($currencyConverter instanceof HistoryInterface) {
    // currency converter supports querying historical data
}

Please or to participate in this conversation.