Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Better Code Design in PHP

Better Code Design in PHP

Are you tired of spending hours reading code just to find the right place to make a small change?

Are you forced to split your application into several just so that devs don't step on each other's toes?

This talk unites theory with practice to show you how to structure your code so that it is easy to read, to test and to maintain. You will step out with concrete ideas of how to improve your code design.

Anna Filina

November 12, 2024
Tweet

More Decks by Anna Filina

Other Decks in Programming

Transcript

  1. © Perforce Software, Inc. Better Code Design in PHP International

    PHP Conference Anna Filina | November 2024
  2. © Perforce Software, Inc. Anna Filina • Coding since 1997

    • PHP, Java, C#, etc. • Zend Professional Services • I fix your legacy • I write your tests • I teach you all my tricks
  3. © Perforce Software, Inc. What Drives My Design • Avoid

    complexity until I need it. • Can I understand the business use case?
  4. © Perforce Software, Inc. Hard to Read $list = $this->repository->fetch(['column1'

    => $value . $seq . $suffix]); $filteredList = $this->filter->removeType($list, 2); $sortedList = $this->sorter->sort($filteredList, ['integers' => true]); $this->database->persist('table1', $sortedList);
  5. © Perforce Software, Inc. Short-Term Rental Marketplace • Search properties

    for rent by city, date and number of guests. • Reserve & pay.
  6. © Perforce Software, Inc. Reservation ReservationService ->reserve() PaymentManager ReservationManager processPayment(data)

    Templating saveReservation(data) confirmReservation(data) html EmailManager payment savePayment(data) confirmReservation(html)
  7. © Perforce Software, Inc. Reservation ReservationService ->reserve() PaymentManager ReservationManager Templating

    EmailManager processPayment(data) saveReservation(data) confirmReservation(data) html payment savePayment(data) confirmReservation(html)
  8. © Perforce Software, Inc. Business Language MakeReservation PaymentProcessor ReservationRepository capture(charge)

    ReservationNotifier add(paidReservation) paymentConfirmation notifyBuyer(paidReservation)
  9. © Perforce Software, Inc. Business Language MakeReservation PaymentProcessor ReservationRepository capture(charge)

    ReservationNotifier add(paidReservation) paymentConfirmation notifyBuyer(paidReservation)
  10. © Perforce Software, Inc. Business Language MakeReservation PaymentProcessor ReservationRepository capture(charge)

    ReservationNotifier add(paidReservation) paymentConfirmation notifyBuyer(paidReservation)
  11. © Perforce Software, Inc. Business Language MakeReservation PaymentProcessor ReservationRepository capture(charge)

    ReservationNotifier add(paidReservation) paymentConfirmation notifyBuyer(paidReservation)
  12. © Perforce Software, Inc. Business Language MakeReservation PaymentProcessor ReservationRepository capture(charge)

    ReservationNotifier add(paidReservation) paymentConfirmation notifyBuyer(paidReservation)
  13. © Perforce Software, Inc. Start in English Scenario: Guest can

    make a reservation Given I selected dates for a property When I submit valid payment details Then I should receive a reservation confirmation via e-mail
  14. © Perforce Software, Inc. Search Scenario Scenario: Find property if

    the city, guests and dates match Given a property "Lviv for 4" in Lviv with 3 beds for 4 guests And the property is available on Jan 1 to Jan 31 When I search a property for 2 adults in Lviv on Jan 1 to Jan 7 Then I should see "Lviv for 4" in the results
  15. © Perforce Software, Inc. Simple Code • No need for

    framework. • No need to design the database. • No need to have a UI. • Code the business rules.
  16. © Perforce Software, Inc. From Gherkin to Code Scenario: Find

    property if the city, guests and dates match Given a property "Lviv for 4" in Lviv with 3 beds for 4 guests And the property is available on Jan 1 to Jan 31 When I search a property for 2 adults in Lviv on Jan 1 to Jan 7 Then I should see "Lviv for 4" in the results
  17. © Perforce Software, Inc. From Gherkin to Design When I

    search a property for 2 adults in Lviv on Jan 1 to Jan 7 Then I should see "Lviv for 4" in the results Handle HTTP Request Return HTTP Response 2 adults in Lviv on Jan 1 to Jan 7 Results containing “Lviv for 4”
  18. © Perforce Software, Inc. First Code $response = [ [

    'name' => 'Lviv for 4', 'price' => '$345 CAD', ] ];
  19. © Perforce Software, Inc. Request/Response Handle HTTP Request Return HTTP

    Response 2 adults in Lviv on Jan 1 to Jan 7 Results containing “Lviv for 4”
  20. © Perforce Software, Inc. Handle Function public function handle(array $request):

    array { return [ [ 'name' => 'Lviv for 4', 'price' => '$345 CAD', ] ]; }
  21. © Perforce Software, Inc. Handler Class final readonly class PropertySearchHandler

    { public function handle(array $request): array { return [ [ 'name' => 'Lviv for 4’, 'price' => '$345 CAD’, ] ]; } } When I search a property [...]
  22. © Perforce Software, Inc. Execute // public/index.php $url = parse_url($_SERVER['REQUEST_URI']);

    $response = match ($url['path']) { '/' => (new PropertySearchHandler())->handle($_GET), }; header('Content-Type: application/json'); echo json_encode($response);
  23. © Perforce Software, Inc. ” ” “A complex system that

    works is invariably found to have evolved from a simple system that worked.” — John Gall
  24. © Perforce Software, Inc. Property final readonly class Property {

    public function __construct( public string $name, public string $price, ) { } }
  25. © Perforce Software, Inc. Usage return match ($request['city']) { 'Lviv'

    => [ new Property('Lviv for 4', '$345 CAD'), ], 'Odesa' => [ new Property('Odesa 4', '$310 CAD'), new Property('Luxury Odesa 4', '$525 CAD'), ], };
  26. © Perforce Software, Inc. SearchCriteria final readonly class SearchCriteria {

    public function __construct( public string $city, // can be validated ) { } }
  27. © Perforce Software, Inc. Problem with City return match ($criteria->city)

    { 'Lviv' => [ new Property('Lviv for 4', '$345 CAD'), ], 'Odesa' => [ new Property('Odesa 4', '$310 CAD'), new Property('Luxury Odesa 4', '$525 CAD'), ], };
  28. © Perforce Software, Inc. Coordinates $coordinates = match ($criteria->city) {

    'Lviv' => new Coordinates(49.8397, 24.0297), 'Odesa' => new Coordinates(46.4825, 30.7233), };
  29. © Perforce Software, Inc. Coordinates $coordinates = match ($criteria->city) {

    'Lviv' => new Coordinates(49.8397, 24.0297), 'Odesa' => new Coordinates(46.4825, 30.7233), }; return match ($coordinates->latitude) { 49.8397 => [ new Property('Lviv for 4', '$345 CAD'), ], 46.4825 => // ..., };
  30. © Perforce Software, Inc. Improvements $coordinates = match ($criteria->city) {

    'Lviv' => new Coordinates(49.8397, 24.0297), 'Odesa' => new Coordinates(46.4825, 30.7233), }; return match ($coordinates->latitude) { 49.8397 => [ new Property('Lviv for 4', '$345 CAD'), ], 46.4825 => // ..., };
  31. © Perforce Software, Inc. SQL SELECT name, price, ST_DISTANCE_SPHERE (

    POINT(:search_longitude, :search_latitude), POINT(longitude, latitude) ) * .001 AS `distance_in_km` FROM `properties` HAVING `distance_in_km` <= :max_distance;
  32. © Perforce Software, Inc. SQL SELECT name, price, ST_DISTANCE_SPHERE (

    POINT(:search_longitude, :search_latitude), POINT(longitude, latitude) ) * .001 AS `distance_in_km` FROM `properties` HAVING `distance_in_km` <= :max_distance;
  33. © Perforce Software, Inc. Problem PropertySearchHandler Lviv, Lviv Oblast, Ukraine

    Convert to coordinates. CitySearchHandler Lviv - Lviv, Lviv Oblast, Ukraine - Lviv Boulevard, Oshawa, ON
  34. © Perforce Software, Inc. Reorganize public function handle(array $request): array

    { $searchCriteria = SearchCriteria::fromRequest($request); // ... return $this->propertyRepository->find($searchCriteria); }
  35. © Perforce Software, Inc. Problem PropertySearchHandler 49.8397, 24.0297 Longitude: -180

    to +180 Latitude: -90 to +90 CitySearchHandler Lviv Lviv, Lviv Oblast, Ukraine 49.8397 24.0297
  36. © Perforce Software, Inc. Reorganize final readonly class SearchCriteria {

    public function __construct( public string $city, ) { } }
  37. © Perforce Software, Inc. Code is simply a model of

    the business rules and knowledge.