Sunday, 23 April 2023

Apply SOLID principles in PHP

1. Single Responsibility Principle 

- Each class should have only one responsibility

class User extends Model{}

class EmailNotifier {
public function send(User $user, $message) {}
}

// in your controller or service class
$user = User::find($id);
$user->update($request->all());

$emailNotifier = new EmailNotifier();
$emailNotifier->send($user, 'Your information has been updated.');

2. Open/Closed Principle 

- A class should be open for extension but closed for modification

interface PaymentGatewayInterface { public function processPayment($amount);}

class PayPalGateway implements PaymentGatewayInterface {
public function processPayment($amount) {}
}

class StripeGateway implements PaymentGatewayInterface{
public function processPayment($amount) {}
}

class PaymentController extends Controller{
public function process(Request $request, PaymentGatewayInterface $gateway) {}
}

3. Liskov Substitution principle

- Each base class can be replaced by its subclasses

abstract class EmailProvider {
abstract public function addSubscriber(User $user): array;
abstract public function sendEmail(User $user): void;
}

class MailChimp extends EmailProvider {
public function addSubscriber(User $user): array {}
public function sendEmail(User $user): void {}
}

class ConvertKit extends EmailProvider{
public function addSubscriber(User $user): array {}
public function sendEmail(User $user): void {}
}

// you can using baseclass
class AuthController {
public function register(RegisterRequest $request,
EmailProvider $emailProvider) {}
}

// or using subclasses
public function register(RegisterRequest $request,
ConvertKit $emailProvider) {}

* apply: use type, hints and return types, use default values for parameters => to would be immediately flag the error when wrong types

4. Interface Segregation Principle

- Should have many small interfaces instead of a few huge ones 

// not do like this  
interface ProductType{
public function calculatePrice(Product $product): float;
public function decreaseInventory(Product $product): void;
public function calculateTaxes(Product $product): TaxData;
}

// apply Interface Segregation Principle
interface ProductPriceType{
public function calculatePrice(Product $product): float;
}

interface ProductInventoryHandler{
public function decreaseInventory(Product $product): void;
}

interface ProductTaxType{
public function calculateTaxes(Product $product): TaxData;
}

5. Dependency Inversion Principle

- Depend on abstraction, not detail

abstract class MarketDataProvider{
abstract public function getPrice(string $ticker): float;
}

class IexCloud extends MarketDataProvider{
public function getPrice(string $ticker): float {}
}

class Finnhub extends MarketDataProvider {
public function getPrice(string $ticker): float {}
}
 
// using
MarketDataProvider
class CompanyController {
public function show( Company $company,
MarketDataProvider $marketDataProvider) {}
}

Thank you.

References
- https://martinjoo.dev/solid-principles-with-laravel


No comments:

Post a Comment

Golang Advanced Interview Q&A