Blog

21 sierpnia 2015 Bartłomiej Gruszka

7 funkcjonalności, które sprawiają że PHP7 jest rewolucyjny

Tagi: ,

7 funkcjonalności, które sprawiają że PHP7 jest rewolucyjny

Zgodnie z planem język PHP7 zostanie wydany jeszcze w tym roku. Zamknięto już listę planowanych funkcjonalności, które zostaną zaimpleentowane w wersji 7.0. Ostatnio wydano wersję 7.0.0 RC 1.

W tym poście chciałbym przybliżyć najciekawsze – moim zdaniem – zmiany i nowe funkcjonalności, które będą miały największy wpływ na sukces tego języka.

0. Wydajność

Jeden z głównych twórców języka PHP, Dymitry Stogov, w udzielonym niedawno wywiadzie poinformował, że wersja 7.0 jest w benchmarkach 14x szybsza niż wersja 5.0, dla przypomnienia: wydana w 2004 roku. W realnych testach najpopularniejsze frameworki okazują się działać około 70% szybciej, w porównaniu do ostatniej stabilnej wersji.

W popularnym benchmarku, polegającym na generowaniu zbioru Mandelbrota, najnowsza wersja PHP okazuje się bić na głowę języki takie jak: Python, Ruby czy Perl.

Ten ogromny przyrost prędkości, w połączeniu z ograniczeniem zużywania zasobów systemowych pozwoli, nie tylko na przyspieszenie istniejących aplikacji, ale i na znaczne zmieniejszenie wymaganej infrastruktury, przy zachowaniu stałej wydajności. A to konkretny argument finansowy, przemawiający za nową wersją języka.

1. Ujednolicenie składni

Jednym z głównych zarzutów, stawianych od zawsze jako argument przeciwko językowi PHP jest brak konsekwecji w jego składni. Jedne operacje były dozwolone, podobne do nich powodowały błędy składniowe. Na przykład od wersji 5.4 umożliwiono natychmiastową dereferencję tablicy zwracanej z metody, jednak dalej nie było możliwe natychmiastowe wywołanie zwracanej funkcji. PHP7 wprowadza przełom w tej kwestii. Dodano wiele operacji, które sprawiają, że składnia staje się bardziej spójna i jednolita, pozwoli to między innymi na pełniejsze wykorzystanie programowania funkcyjnego. Poniższe przykłady najlepiej zilustrują zmiany, które zostały wprowadzone.

// zagnieżdżenie wywoływania funkcji - funkcje wyższego rzędu
$apply = function ($fun) {
    return function ($a) use ($fun) {
        return $fun($a);
    };
};

$add = function ($x) {
    return function ($y) use ($x) {
        return $x + $y;
    };
};

echo $apply($add)(2)(3);

PHP 7: 5
PHP 5.6: Parse error: syntax error, unexpected ‘(‘, expecting ‘,’ or ‘;’ in …

echo (function ($a) {
    return $a + 3;
})(2);

PHP 7: 5
PHP 5.6: Parse error: syntax error, unexpected ‘(‘, expecting ‘,’ or ‘;’ in …

Warto zwrócić uwagę, że ta zmiana powoduje złamanie kompatybilności wstecznej, stary kod musi zostać przeglądnięty i dostosowany do nowych realiów. Więcej przeczytać można w RFC: Uniform Variable Syntax.

2. Wyjątki zamiast błędów krytycznych

PHP7 wprowadza bardzo istotną zmianę w wewnętrznej obsłudze błędów. Od wersji 7 błędy krytyczne są zgłaszane jako wyjątki silnika, które będą mogły być łapane i obsługiwane jak wszystkie pozostałe wyjątki. Rozwiązanie to powoduje szereg usprawnień względem klasycznej obsługi błędów. Przede wszystkim pozwala na przechwytywanie błędów, które wcześniej powodowały natychmiastowe zatrzymanie wykonania programu. Przykładem, który dobrze ilustruje problem jest błąd krytyczny podczas wykonywania testów, obecnie błąd krytyczny w jednym z przypadków testowych powoduje zatrzymanie całej procedury testowania. Co więcej, wyjątki dostarczą ślad stosu, który ułatwi debugowanie źródła błędów.

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

try {
    echo add(2, "trzy");
} catch (EngineException $e) {
    echo $e->getMessage(); //Argument 2 passed to add() must be of the type integer, string given ...
}

Wprowadzone zostają dwa nowe typy wyjątków, dla wewnętrznych EngineException błędów silnika oraz ParseException dla błędów składniowych, więcej informacji można znaleźć w RFC: Exceptions in the engine.

3. Deklaracje dla typów skalarnych

Jedną z największych zmian w PHP7 jest dodanie deklaracji dla typów skalarnych, deklarowane będą mogły być łańcuchy znaków (string), liczby całkowite (int) i zmiennoprzecinkowe (float) oraz typy logiczne (boolean). Uzupełniają one dodane w poprzednich wersjach deklaracje dla klas, interfejsów, tablic i typu callable.

Sprawdzanie typów dostępne będzie w dwóch wersjach, domyślnym coercive – dopuszczającym rzutowanie  i strict – dopuszczająca tylko dokładny typ. Sprawdzanie typów konfiguruje się dla każdego pliku osobno, w celu odblokowania trybu strict należy w na samej górze pliku umieścić linię:

declare(strict_types=1);

Gdy dopasowanie typu nie powiedzie się, zostanie rzucony wyjątek TypeError, co także jest nowością wprowadzoną w PHP7.

declare(strict_types=1);

function multiply(float $x, float $y)
{
    return $x * $y;
}

function add(int $x, int $y)
{
    return $x + $y;
}

var_dump(multiply(2, 3.5)); // float(7)
var_dump(add('2', 3)); // Fatal error: Uncaught TypeError: Argument 1 passed to add() must be of the type integer, string given...

Więcej przeczytać można w RFC: Scalar Type Declarations.

4. Deklaracje dla typów zwracanych

Kolejną przełomową zmianą w PHP7 jest wprowadzenie deklaracji dla typów zwracanych. Dostępny jest szereg typów, które są obsługiwane: ciągi znaków (string), liczby całkowite (int) i zmiennoprzecinkowe (float), typy logiczne (bool),  tablice (array), typ callable, typ self (tylko dla metod), typ parent (tylko dla metod), domknięcia (Closure), a także klasy i interfejsy.

Deklaracje dla typów zwracanych, podobnie jak dla typów skalarnych posiadają dwa tryby: coercive – dopuszczającym rzutowanie  i strict – tylko dokładny typ, konfigurowane analogicznie jak w poprzednim przypadku.

Deklaracji typu zwracanego dokonuje się poprzez umieszczenie dwukropka i nazwy typu po liście argumentów funkcji:

function add(int $x, int $y) : int
{
    return $x + $y;
}

Gdy dopasowanie typu nie powiedzie się, podobnie jak w przypadku deklaracji dla typów statycznych, zostanie rzucony wyjątek TypeError.

declare(strict_types=1);

function multiply(float $x, float $y) : float
{
    return $x * $y;
}

function add(int $x, int $y) : string
{
    return $x + $y;
}

var_dump(multiply(2, 3.5)); // float(7)

var_dump(add(2, 3)); // Fatal error: Uncaught TypeError: Return value of add() must be of the type string, integer returned

Więcej przeczytać można w RFC: Return Type Declarations.

5. Klasy anonimowe

Klasy anonimowe, znane między innymi z języka Java są także dostępne w PHP7. Pozwalają one na utworzenie instancji klasy w miejscu i natychmiastowe przekazanie obiektu, na przykład do funkcji. Są wyjątkowo użyteczne gdy instancja obiektu wykorzystywana jest tylko i wyłącznie w jednym miejscu.

interface Comparator {
    public function compare($a, $b);
}

// PHP5+
class SimpleComparator implements Comparator
{
    public function compare($a, $b)
    {
        return $a === $b;
    }
}

$system->setComparator(new SimpleComparator());

// PHP7
$system->setComparator(
    new class implements Comparator {
        public function compare($a, $b)
        {
            return $a === $b;
        }
    }
);

Więcej w RFC: Anonymous Classes.

6. Nowe operatory: połączonego porównania (Combined Comparison / Spaceship) oraz trójkowy isset (Trenary isset / Null Coalesce)

PHP7 wprowadza dwa nowe operatory, które pozwalają łatwiej przeprowadzać typowe operacje.

Pierwszy z nich, operator połączonego porównania, nazywany też spaceship (statek kosmiczny) pozwala na skrócone trójkowe (większy, równy, mniejszy) porównywanie wartości.

var_dump(1 <=> 2); // int(-1)

var_dump(‘PHP7’ <=> ‘PHP7’); // int(0)

var_dump(‘PHP7’ <=> ‘PHP6’); // int(1)

var_dump([1,2,3] <=> [3,4,5]); // int(-1)

Dla ciągów znaków wykonywanie jest porównanie leksykalne. Dla obiektów zachowanie tego operatora nie zostało zdefiniowane.

Drugi z operatorów, trójkowy isset, pozwala na szybkie sprawdzenie czy wartość istnieje i nie jest równa null, w przeciwnym przypadku pozwala zwrócić wartość domyślną.

$page = $_GET['page'] ?? 1; // $page = isset($_GET['page']) ? $_GET['page'] : 1;

Operator ten może być łączony w łańcuchy:

$email = $_POST['email'] ?? $user['email'] ?? 'user@esky.pl';

Więcej o nowych operatorach przeczytasz w RFC: Combined Comparison (Spaceship) Operator i RFC: Null Coalesce Operator.

7. Grupowanie deklaracji use

Grupowanie deklaracji use pozwala w wygodny, skrócony sposób importować nazwy z tej samej przestrzeni nazw.

// PHP5+
use Esky\Blog\Post;
use Esky\Blog\Author as User;
use Esky\Blog\Comment;

// PHP7
use Esky\Blog\{Post, Author as User, Comment};

Więcej w RFC: Group Use Declarations.

Podsumowanie

Poza niewątpliwym skokiem wydajności i ograniczeniem zużycia pamięci, PHP7 wprowadza wiele przełomowych funkcjonalności. Wprowadzają one język na wyższy poziom, a programistom pozwalają na bardziej konsystentne wykorzystywanie jego możliwości. W mojej ocenie pozwoli to na “drugie życie” dla PHP i być może przekona część sceptyków do samego języka.

Ciekaw jestem jakie widzisz praktyczne zastosowania dla nowości wprowadzonych w języku PHP7?

Źródła / Do poczytania

https://www.zend.com/en/resources/php-7

https://github.com/tpunt/PHP7-Reference

https://www.zend.com/en/resources/php7_infographic

https://kinsta.com/blog/hhvm-vs-php-7/

https://blog.amasty.com/php-7-and-script-languages-future-insights-from-lead-zend-com-developer/

Zobacz na blogu

09.09.2022
Marcin Jahn
It’s Not Just HTTP It’s Not Just HTTP

In today’s world of cloud-based solutions, distributed systems, and microservices-based architectures, network communication is a...

23.08.2022
Adam Mrowiec
Konferencja IPC 2022 Berlin Konferencja IPC 2022 Berlin

Pandemia wreszcie się kończy, dlatego w tym roku postanowiliśmy wrócić do naszych wyjazdów na konferencje....