1

I am developing an open source project in Laravel. I want to create framework which people can create their own payment gateways for their needs by implementing generic interfaces and ui will interact with that payment gateway. Which is the best way restrict return value from interface.

Right now I'm using this technic:

interface PaymentGateway
{
  public function savePaymentPlan($email, $name, $surname, $phone, $cardNum, $cardHolderName, $cardExpriy, $amount, $checkoutDay): SavePaymentPlanResult;
}
interface SavePaymentPlanResultInterface{
  public function getCardToken();
  public function setCardToken($token);
}
class SavePaymentPlanResult implements SavePaymentPlanResultInterface{
  private $cardToken = null;

  public function setCardToken($token){
    $this->cardToken = $token;
  }

  public function getCardToken(){
    return $this->cardToken;
  }
}

And using all of them like that:

class StrapiPaymentGateway implements PaymentGateway{
   public function savePaymentPlan($email, $name, $surname, $phone, $cardNum, $cardHolderName, $cardExpriy, $amount, $checkoutDay): SavePaymentPlanResult {
      $savePaymentPlanResult = new SavePaymentPlanResult;
      ...
      ...
      $savePaymentPlanResult->setToken('<some-token>')
      ...
      ...
      return $savePaymentResult;
   }
}

Inside controller

class Controller {
    test(){
        $strapiPaymentGateway = new StrapiPaymentGateway();
        $token = $strapiPaymentGateway->getToken();
    }
}

Is it true way to do that? Because so many stuff you have to do just restrict return value?

Thanks for your answer.

  • Yes, to restrict return type or passed parameter type you _must_ define it's type. No other way (except for internal checks for types) – Justinas Aug 02 '22 at 08:29
  • A function [shouldn't have too many arguments](https://www.informit.com/articles/article.aspx?p=1375308). Looking at `savePaymentPlan`, it could definitely benefit from [refactoring](https://softwareengineering.stackexchange.com/q/331803/9457), especially as all the fields are associated with real-world objects, and thus should be encapsulated in a class. The method name itself suggests the class for the argument: `PaymentPlan`. Note that many of the fields belong to a customer, and thus cry out to be put in a `Customer` class (which is then referenced by a `PaymentPlan`). – outis Aug 03 '22 at 02:39
  • ... The payment info fields should go in their own class (e.g. `PaymentInfo`). Note that a payment plan should be for a series of payments. If the `savePaymentPlan` is for a one-time payment, especially if not delayed, it's more sensical to call it payment information, not a payment plan. – outis Aug 03 '22 at 02:41

1 Answers1

0

Yes, defining the return type in the interface is the best way to enforce it.

However, if you want to be strict about coding towards an interface the savePaymentPlan method should return the SavePaymentPlanResultInterface instead of the concrete type. Then again, if you know you will only have one SavePaymentPlanResult, you don't necessarily need the SavePaymentPlanResultInterface.

On a side note: your naming is a bit inconsistent. You seem to add the Interface for interfaces, but then PaymentGateway interface is just called PaymentGateway.

Gordon
  • 312,688
  • 75
  • 539
  • 559