PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

PHP typing in 7.x, strict_types, PHPStan, preparing for PHP 7.4

by Henryk Tews / Tuesday, 11 June 2019 / Published in PHP

PHP’s type system evolved gradually from 5.x. PHP 7.x strengthened it significantly – parameter typing, return types, nullable types, and union types on the horizon. PHP 7.4 adds typed properties. A good moment to summarise the state of typing and show best practices worth adopting today.

What we have in PHP 7.x today

<?php

declare(strict_types=1);

class OrderCalculator
{
    public function calculateTotal(array $items, float $taxRate): float
    {
        $subtotal = array_sum(array_column($items, 'price'));
        return $subtotal * (1 + $taxRate);
    }

    public function applyDiscount(float $price, ?float $discount): float
    {
        if ($discount === null) {
            return $price;
        }
        return $price - $discount;
    }

    public function logOrder(int $orderId): void
    {
        // write to log
    }
}

declare(strict_types=1) – use it always

Without strict mode PHP silently coerces types – string “5” passed to an int parameter gets converted to 5 with no error. With strict mode you get a 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) must be the first statement in the file, before namespace and use. It only affects function calls in that file.

Typing class properties today – via docblock and constructor

<?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; }
}

Returning interface types instead of concrete classes

<?php

declare(strict_types=1);

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

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

    // Return the interface, not Model\Product
    public function getById(int $id): ProductInterface
    {
        return $this->productRepository->getById($id);
    }
}

Typing arrays – limitations and workarounds

<?php

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 understands @var ProductInterface[] and suggests methods when iterating. This does not enforce types at runtime, but greatly aids static analysis with PHPStan or Psalm.

PHPStan – static analysis as a safety net

composer require --dev phpstan/phpstan

# Level 5 (scale 0-8, higher = stricter)
vendor/bin/phpstan analyse src --level=5

PHPStan catches type errors and calls to non-existent methods without running the code. For Magento 2 use the bitExpert/phpstan-magento package for platform-specific rules.

Summary

PHP typing is not a formality – it catches errors at write time instead of in production. declare(strict_types=1) costs one line and eliminates an entire class of silent coercions. In Magento 2, where code flows through DI, plugins and repositories – more types means easier problem diagnosis.

About Henryk Tews

What you can read next

PHP 7.2 – object type hint, sodium instead of mcrypt, deprecations

© 2026 Created by

TOP
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 Always active
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.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}