• Czas czytania ~6 min
  • 24.05.2023

Wprowadzenie

Jeśli jesteś programistą PHP, prawdopodobnie widziałeś oświadczenie declare(strict_types=1) na początku niektórych plików PHP.

Kiedy po raz pierwszy zobaczyłem to oświadczenie, nie miałem pojęcia, co ono robi. Zakładałem, że to jakiś komentarz, a może stara składnia PHP, która była przed moim czasem, ale myliłem się (bardzo źle!).

W tym artykule Quickfire omówimy, co declare(strict_types=1) to jest i jak może pomóc w poprawie bezpieczeństwa typów kodu PHP.

Co to jest declare(strict_types=1)?

declare(strict_types=1) is a statement that enforces strict typing in PHP applications.

Gdy użyjesz tej instrukcji, PHP wykona ścisłe sprawdzanie parametrów funkcji i zwraca typy. Oznacza to, że jeśli funkcja oczekuje określonego typu parametru lub zwracanej wartości, PHP zgłosi błąd, jeśli zostanie użyty niewłaściwy typ.

Weźmy prosty przykład, który nie używa declare(strict_types=1):Teraz powiedzmy, że wywołaliśmy tę funkcję z parametrami ciągu:

function add(int $a, int $b): int
{
    return $a + $b;
}

echo add('1', '2');
 
// Output:
// 3

PHP will happily convert the string parameters to integers and return the result 3.

W niektórych przypadkach możesz być całkowicie w porządku z tym zachowaniem. Ale może to mieć pewne niezamierzone konsekwencje, których się nie spodziewałeś i które mogą powodować błędy w Twojej aplikacji.

Wyobraźmy sobie jednak, że chcieliśmy użyć declare(strict_types=1) w tym przykładzie. Możemy to zrobić, dodając następującą instrukcję na górze pliku:Teraz, jeśli wywołamy add funkcję z parametrami string, PHP wyrzuci błąd:

declare(strict_types=1);
 
function add(int $a, int $b): int
{
    return $a + $b;
}

echo add('1', '2');
 
// Output:
// Fatal error: Uncaught TypeError: Argument 1 passed to add() must be of the type int, string given
As we can see here, PHP has thrown an error because the add function expected integers to be passed, but received strings instead.

Podobnie, PHP również wyrzuci błędy, jeśli włączone jest ścisłe sprawdzanie typu i spróbujemy zwrócić niewłaściwy typ danych z metody. Załóżmy na przykład, że nasza add funkcja akceptuje teraz pływaki zamiast liczb całkowitych i że nie mamy włączonego ścisłego sprawdzania typu:Możemy wtedy wywołać funkcję w następujący sposób:

function add(float $a, float $b): int
{
    return $a + $b;
}

Odpowiedź, którą powinniśmy otrzymać,

echo add(1.25, 2.25);
 
// Output:
// 3
Did you spot the problem in the output?

to 3.5. Ponieważ jednak zdefiniowaliśmy typ zwrotu jako int, przekonwertowaliśmy zmiennoprzecinkowy (który miał zostać zwrócony) na liczbę całkowitą i straciliśmy precyzję. Jak możesz sobie wyobrazić, może to powodować pewne problemy w innych częściach naszej aplikacji, w których używamy tego wyniku, a precyzja mogła być potrzebna.

Teraz rozwiążmy ten problem za pomocądeclare(strict_types=1):

declare(strict_types=1);
 
function add(float $a, float $b): int
{
    return $a + $b;
}
Odpowiedź, którą powinniśmy otrzymać,
echo add(1.25, 2.25);
 
// Output:
// Fatal error: Uncaught TypeError: add(): Return value must be of type int, float returned

Jak widzimy, włączając ścisłe sprawdzanie typu, możemy zauważyć, że funkcja nie zwraca poprawnego typu danych. Jest to świetne, ponieważ może to być podkreślenie możliwego błędu w naszym kodzie, o którym nie wiedzieliśmy. Następnie moglibyśmy podjąć niezbędne kroki w celu:

  • Zaktualizuj typy zwracane, jeśli są niepoprawne
  • Zaktualizuj wskazówki dotyczące typu, jeśli są niepoprawne
  • Zaktualizuj treść funkcji, aby zwracała poprawny typ danych, jeśli jest nieprawidłowy
  • Napraw wszelkie błędy w kodzie wywołującym funkcję, które mogą przekazywać do niego niepoprawny typ danych

Czy powinienem używać declare(strict_types=1)?

Osobiście uważam, że dobrym pomysłem jest użycie declare(strict_types=1) we wszystkich plikach PHP. Kiedyś myślałem, że samo posiadanie podpowiedzi do typów i typów zwracanych wystarczy, aby upewnić się, że prawidłowe typy danych są przekazywane, ale od tego czasu zmieniłem zdanie. Czuję się znacznie pewniej w moim kodzie, gdy go używam i znalazłem kilka błędów w wyniku jego użycia (w szczególności podczas dodawania go declare(strict_types=1) do starszych baz kodu).

Odkąd się o tym dowiedziałem, mam zwyczaj używania go w każdym nowym pliku PHP, który tworzę. W rzeczywistości zaktualizowałem wszystkie szablony w mojej konfiguracji PhpStorm , aby były automatycznie dołączane na górze każdego tworzonego pliku. Na przykład, oto szablon, który jest używany podczas tworzenia nowej klasy PHP: Jest to naprawdę przydatne,

 <?php
 
 declare(strict_types=1);
 
 #parse("PHP File Header.php")
 
 #if (${NAMESPACE})
 namespace ${NAMESPACE};

 #end
class ${NAME} {

}

ponieważ zachęca mnie do dalszego używania declare(strict_types=1) bez konieczności wprowadzania ręcznych zmian po utworzeniu pliku (o czym zdecydowanie zapomniałbym!).

Dla każdego z moich czytelników Laravel, możesz również opublikować kody pośredniczące , które są używane do tworzenia plików PHP podczas uruchamiania poleceń Artisan, takich jak php artisan make:controller. Publikując zalążki, możesz je edytować i dodawać declare(strict_types=1) na górze. Oznacza to, że pliki utworzone za pomocą poleceń Artisan będą tworzone z włączonymi już bardziej rygorystycznymi zabezpieczeniami typu.

Oczywiście, jeśli zamierzasz dodać ściślejsze sprawdzanie typu do istniejących plików, zdecydowanie zalecałbym najpierw posiadanie dobrej jakości zestawu testów. Twój kod PHP mógł zezwalać na przekazywanie nieprawidłowych typów danych bez zgłaszania błędów. Ale po włączeniu ścisłego sprawdzania typu kod stanie się znacznie mniej wybaczający i może zacząć zgłaszać błędy. Może to spowodować nieoczekiwaną awarię aplikacji dla użytkowników.

Może się również okazać, że musisz refaktoryzować część kodu, aby był zgodny z declare(strict_types=1)programem . Nie uważam tego jednak za coś złego. Zamiast tego postrzegałbym to jako okazję do poprawy jakości kodu.

Aby pomóc w procesie dodawania declare(strict_types=1) do kodu, możesz użyć narzędzia takiego jak PHPStan, które może wychwycić te niedopasowania typów.

Mamy

nadzieję, że ten artykuł dał ci szybki przegląd tego, co declare(strict_types=1) jest i jak może pomóc w poprawie bezpieczeństwa typu kodu PHP.

Jeśli podobał Ci się ten post, chciałbym o tym usłyszeć. Podobnie, jeśli masz jakieś opinie, aby ulepszyć przyszłe, chciałbym to również usłyszeć.

Możesz być także zainteresowany sprawdzeniem mojego 220+ stronicowego ebooka "Battle Ready Laravel", który obejmuje podobne tematy bardziej szczegółowo.

Jeśli jesteś zainteresowany otrzymywaniem aktualizacji za każdym razem, gdy publikuję nowy post, zapisz się do mojego biuletynu poniżej.

Buduj niesamowite rzeczy! 🚀

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

O

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297