1final class ShippingCalculator
2{
3 public function quote(Order $order): Money
4 {
5 switch ($order->carrier) {
6 case 'nova_poshta':
7 $base = 60 + $order->weight * 12;
8 return Money::uah($order->cod ? $base + 20 : $base);
9 case 'ukrposhta':
10 return Money::uah(35 + $order->weight * 8);
11 case 'meest':
12 $zone = $this->zones->for($order->city);
13 return Money::uah($zone->rate * $order->weight);
14 // case 'rozetka': ...
15 default:
16 throw new UnknownCarrier($order->carrier);
17 }
18 }
19}
1<?php
2
31interface ShippingRate
4{
5 public function quote(Order $order): int;
6}
7
82final class NovaPoshtaRate implements ShippingRate
9{
10 public function quote(Order $order): int
11 {
12 return 60 + $order->weight * 12;
13 }
14}
15
16final class UkrposhtaRate implements ShippingRate
17{
18 public function quote(Order $order): int
19 {
20 return 35 + $order->weight * 8;
21 }
22}
23
24final class Checkout
25{
263 public function __construct(private ShippingRate $rate) {}
27
28 public function total(Order $order): int
29 {
30 return $order->sum + $this->rate->quote($order);
31 }
32}
33
34final class Order
35{
36 public function __construct(public int $sum, public int $weight) {}
37}
38
39$order = new Order(sum: 1200, weight: 3);
40
414foreach ([new NovaPoshtaRate, new UkrposhtaRate] as $rate) {
42 echo str_pad($rate::class, 16), (new Checkout($rate))->total($order), " грн\n";
43}