PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Typowanie w PHP 7.x, strict_types, PHPStan, przygotowanie na PHP 7.4

by Henryk Tews / wtorek, 11 czerwca 2019 / Opublikowano w PHP

System typów w PHP rozwijał się stopniowo od wersji 5.x. PHP 7.x znacznie go wzmocnił – mamy typowanie parametrów, typowanie zwracanych wartości, nullable types i union types na horyzoncie. PHP 7.4, które pojawi się pod koniec 2019, doda typed properties. To dobry moment, żeby podsumować stan typowania w PHP i pokazać dobre praktyki, które warto stosować już dziś.

Co mamy w PHP 7.x dziś

<?php

declare(strict_types=1); // wymuszaj strict mode na poziomie pliku

class OrderCalculator
{
    // Typowanie parametrów i wartości zwracanej
    public function calculateTotal(array $items, float $taxRate): float
    {
        $subtotal = array_sum(array_column($items, 'price'));
        return $subtotal * (1 + $taxRate);
    }

    // Nullable type - parametr może być null
    public function applyDiscount(float $price, ?float $discount): float
    {
        if ($discount === null) {
            return $price;
        }

        return $price - $discount;
    }

    // Void - metoda nic nie zwraca
    public function logOrder(int $orderId): void
    {
        // zapis do logu
    }
}

declare(strict_types=1) – używaj zawsze

Bez strict mode PHP będzie po cichu rzutować typy – string „5” przekazany do parametru int zostanie skonwertowany do liczby 5 bez żadnego błędu. Z strict mode dostaniesz TypeError:

<?php

declare(strict_types=1);

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

add(2, 3);     // 5 - ok
add(2.5, 3);   // TypeError: Argument #1 must be of type int, float given
add("2", 3);   // TypeError: Argument #1 must be of type int, string given

declare(strict_types=1) musi być pierwszą instrukcją w pliku, przed namespace i use. Dotyczy tylko wywołań funkcji w danym pliku – nie wpływa na biblioteki zewnętrzne.

Typowanie właściwości klas już dziś – przez docblock i konstruktor

PHP 7.4 wprowadzi typed properties (public int $id), ale już teraz możesz wymuszać typy przez konstruktor i docblock:

<?php

declare(strict_types=1);

class Product
{
    /** @var int */
    private $id;

    /** @var string */
    private $name;

    /** @var float */
    private $price;

    /** @var string|null */
    private $description;

    public function __construct(
        int $id,
        string $name,
        float $price,
        ?string $description = null
    ) {
        $this->id          = $id;
        $this->name        = $name;
        $this->price       = $price;
        $this->description = $description;
    }

    public function getId(): int          { return $this->id; }
    public function getName(): string     { return $this->name; }
    public function getPrice(): float     { return $this->price; }
    public function getDescription(): ?string { return $this->description; }
}

To wzorzec, który już dziś warto stosować w modułach Magento 2 – szczególnie w Data Models implementujących Data Interfaces. Typy w konstruktorze dają Ci wczesne wykrywanie błędów, a docblock wspiera autouzupełnianie w PHPStorm.

Zwracanie typów interfejsów zamiast klas konkretnych

Dobra praktyka przy typowaniu zwracanych wartości – zwracaj interfejs, nie konkretną klasę. Twój kod staje się bardziej elastyczny i łatwiejszy do mockowania w testach:

<?php

declare(strict_types=1);

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;

class ProductService
{
    public function __construct(
        private ProductRepositoryInterface $productRepository
    ) {}

    // Zwracamy interfejs, nie Model\Product
    public function getById(int $id): ProductInterface
    {
        return $this->productRepository->getById($id);
    }

    // Zamiast: public function getById(int $id): \Magento\Catalog\Model\Product
}

Typowanie tablic – ograniczenia i obejścia

PHP nie pozwala na typowanie zawartości tablicy – int[] nie jest poprawnym type hintem. Możesz to obejść przez docblock lub przez własne kolekcje:

<?php

declare(strict_types=1);

class ProductCollection
{
    /** @var ProductInterface[] */
    private array $items = [];

    public function add(ProductInterface $product): void
    {
        $this->items[] = $product;
    }

    /**
     * @return ProductInterface[]
     */
    public function all(): array
    {
        return $this->items;
    }

    public function count(): int
    {
        return count($this->items);
    }
}

PHPStorm rozumie @var ProductInterface[] i podpowiada metody przy iteracji po all(). To nie wymusza typów w runtime, ale znacznie ułatwia pracę ze statyczną analizą kodu (PHPStan, Psalm).

PHPStan – statyczna analiza jako siatka bezpieczeństwa

Warto dodać PHPStan do projektu jako narzędzie CI:

composer require --dev phpstan/phpstan

# Analiza na poziomie 5 (skala 0-8, im wyżej tym bardziej rygorystycznie)
vendor/bin/phpstan analyse src --level=5

PHPStan wyłapuje błędy typów, wywołania nieistniejących metod i wiele innych problemów bez uruchamiania kodu. Dla Magento 2 dostępne są gotowe reguły przez pakiet bitExpert/phpstan-magento.

Podsumowanie

Typowanie w PHP to nie formalność – to narzędzie, które wyłapuje błędy na etapie pisania kodu zamiast na produkcji. declare(strict_types=1) kosztuje jedną linię, a eliminuje całą klasę cichych konwersji typów. W kontekście Magento 2, gdzie kod przechodzi przez warstwy DI, pluginów i repository – im więcej typów, tym łatwiejsza diagnostyka problemów.

About Henryk Tews

Co możesz przeczytać następne

Interpreter w PHP – własna gramatyka reguł rabatowych, parser, drzewo wyrażeń
PHP 8.4 ostatnie RC – Lazy Objects, BcMath\Number, Dom\HTMLDocument
PHP 8.2 po premierze – readonly classes w praktyce, deprecacje, Rector, checklist migracji
  • Publikacje
  • O autorze
  • Kontakt

© 2026 Created by

GÓRA
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Zawsze aktywne
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Zarządzaj opcjami
  • Zarządzaj serwisami
  • Zarządzaj {vendor_count} dostawcami
  • Przeczytaj więcej o tych celach
Zobacz preferencje
  • {title}
  • {title}
  • {title}