Dan Gurgui
Dan GurguiCentre of Excellence Lead @ i6 Group

Funkcje PHP 8, które mogą Ci zaszkodzić

Poznaj funkcje PHP 8, których nieumiejętne użycie może zaszkodzić Twojemu kodowi.
25.01.20214 min
Funkcje PHP 8, które mogą Ci zaszkodzić

PHP to język o wątpliwej reputacji. W ciągu ostatnich kilku lat pojawiło się jednak wiele zmian, które zwiększyły jego wydajność i podkreśliły wagę programowania obiektowego. PHP 8, który jest najnowszym wydaniem major, kontynuuje to dzieło, dostarczając masę nowych funkcji. W PHP 8 mamy sporo fajnych funkcji, takich jak kompilator Just in Time, który poprawia wydajność, promocja właściwości konstruktorów, czy ustrukturyzowane metadane. 

Niektóre z tych funkcji mogą nam niestety zaszkodzić, jeśli będziemy ich niepoprawnie używać. Oto 5 przykładów takich negatywów oraz jak ich unikać:

Null safe operator 

Operator ten zaoszczędzi Ci sporo pisania kodu, zwłaszcza w aplikacjach, które mają sporo logiki biznesowej. Jest on też bardzo zrozumiały: jeśli coś w wywołaniu łańcuchowym jest nullem, to znaczy, że wszystko będzie nullem. 

Zaoszczędzi Ci nie tylko trochę pisania kodu, ale również wysiłku umysłowego przy ciężkich wywołaniach. Operator ten jest obecny też w innych językach (JS i C# mają go razem z funkcją short-circuit). Kiedy więc null safe operator zaczyna nam szkodzić? 

/** PHP 7 */
$country = null;
if ($session !== null) {
 $user = $session->user;
 if ($user !== null) {
   $address = $user->getAddress();
    if ($address !== null) {
       $country = $address->country;
     }
   }
}
/** PHP 8 */
$country = $session?->user?->getAddress()?->country;


W powyższym przykładzie widać, że operator ten jest nadużywany. Kiedy przyjdzie Ci debugować, to nie będziesz wiedzieć, która rzecz jest nullem, co sprawi, że szukanie problemów będzie prawdziwym wyzwaniem. Co jest nullem? To będzie session, czy address? A może to user?

Oto jak unikać tych szkód:

  • Trzymaj się definicji typów, tak mocno, jak tylko możesz. Jeśli wiesz, że zmienna nie będzie nullem to użyj odpowiednio jej typów. 
  • Ogranicz użycie null safe operator do maksymalnie dwóch razy na wywołanie - łatwiej będzie wtedy debugować
  • Uważnie pracuj z nullami, implementując logikę, która zapobiega wywołaniom na nullach

Argumenty nazwane

Przypomniała mi się pewna dyskusja o maksymalnej liczbie argumentów, którą dana metoda może przyjąć. Razem z moim współpracownikiem chcieliśmy narzucić pewne standardy kodowania i pomyśleliśmy o tej zasadzie. Mieliśmy zły zwyczaj dodawania coraz większej liczby parametrów do naszych metod tak jak zresztą cały zespół. 

Masz nową logikę? Dodaj parametr, opakuj go w if i skończ z jedną z najgorszych praktyk. Zamiast robić coś takiego, lepiej jest zawrzeć te parametry wewnątrz danego obiektu. Oto właśnie rule of three. Oznacza to tyle, że w metodzie powinny być zdefiniowane maksymalnie 3 parametry - wszystko ponadto powinno zostać zawarte w obiekcie. Opcja nazwanych argumentów, którą dodano do PHP 8, zniechęca do tej zasady. 

Zamiast tworzyć obiekt z getterami, setterami i logiką dla null assertion, programiści zaczną dodawać nowe argumenty, bo tak im będzie łatwiej. Bez jasno określonych i rygorystycznych standardów, metody mogą się rozrastać i wprowadzać za dużo złożoności do kodu. Co możemy zatem zrobić, aby tego uniknąć?

  • Narzucić liczbę argumentów, jaką może mieć dana metoda 
  • Zawsze zawierać dane i logikę wewnątrz obiektów

Union Types

Od kilku lat PHP idzie w stronę bardziej rygorystycznego typowania, co pokazuje, że język staje się bardziej dojrzały i zostawia wszystkie złe praktyki za sobą. Przestrzenie nazw, cechy (albo traits), deklaracje typów skalarnych, deklarowanie zwracanego typu, klasy anonimowe itd. były tego wyrazem. W tym kontekście mamy jeszcze unie:

public function __construct(
    private int|float|string|null $number
  ) {}


Osobiście uważam, że to jedna z najgorszych rzeczy w PHP 8 - zniechęca do używania interfejsów. Zamiast wymuszać na developerach, aby się trochę bardziej postarali i tworzyli interfejsy (co z kolei wymusza abstrakcyjne myślenie), to unie pozwalają na totalną samowolkę. Próbowałem znaleźć sytuację, w której użycie unii będzie korzystne, ale nie udało mi się. 

Korzystanie z tej funkcji może zrobić coś dobrego, jeśli masz jakąś bardzo starą apkę i próbujesz ją przenieść do PHP 8. Zamiast tego powinno się jednak rozdzielać metody, zamiast dodawać jakieś dziwne typy. 

Może coś Ci to da przy późniejszej refaktoryzacji, ale dlaczego w sumie nie robić tego od razu? Gdybym musiał dokonać aktualizacji do PHP 8, to poprosiłbym moje zespoły o dodanie tej funkcji do lintera, który uniemożliwia korzystanie z unii lub przynajmniej ogranicza je do maksymalnie dwóch.

Typy mieszane

Najlepsze zostawiłem na koniec - a raczej najgorsze. Jeśli unie są złe, to typy mieszane to po prostu jakiś koszmar. To trochę tak, jakby PHP Ci mówiło, że możesz robić złe rzeczy na więcej niż jeden sposób.

public function __construct(
    private mixed $number
  ) {}


Oto ekwiwalent skomplikowanej unii:

public function __construct(
    private array|bool|callable|int|float|null|object|resource|string $number
  ) {}


Wiem, że są programiści, którzy przyjrzą się oficjalnej dokumentacji, przeczytają RFC dotyczące tego nowego typu, a nawet pójdą o krok dalej i postarają się zrozumieć, dlaczego ten typ został w ogóle dodany. Ale jednocześnie wiem, że jest jeszcze więcej programistów, którzy źle wykorzystają tę funkcję i będą jej nadużywać.

Ogólnie PHP 8 dodaje kilka funkcji, które w rękach niedoświadczonych programistów mogą narobić sporo złego. Jeśli nie wiesz, jak z nich poprawnie korzystać, aby sobie nie zaszkodzić, to lepiej ich unikać.


Oryginał tekstu w języku angielskim możesz przeczytać tutaj

<p>Loading...</p>