Система типов ООП
Type Hints для свойств и методов
<?php
declare(strict_types=1);
class UserProfile
{
public string $name;
public int $age;
public ?string $bio = null; // Nullable
public array $hobbies = [];
public bool $active = true;
public function setAge(int $age): void
{
if ($age < 0 || $age > 150) {
throw new InvalidArgumentException("Invalid age: {$age}");
}
$this->age = $age;
}
}
Union Types (PHP 8.0+)
<?php
declare(strict_types=1);
class ApiResponse
{
// Property can be int or string
public int|string $id;
// Method parameters
public function setData(array|string $data): void
{
$this->data = is_string($data)
? json_decode($data, true, 512, JSON_THROW_ON_ERROR)
: $data;
}
// Return type
public function findUser(int $id): User|null // Same as ?User
{
return $this->repository->find($id);
}
// false as type
public function search(string $query): array|false
{
return $this->doSearch($query) ?: false;
}
}
// Special union types
function process(int|float|string $input): int|float
{
return match(true) {
is_int($input) => $input * 2,
is_float($input) => round($input, 2),
is_string($input) => (int)$input,
};
}
Intersection Types (PHP 8.1+)
<?php
declare(strict_types=1);
interface Countable
{
public function count(): int;
}
interface Serializable
{
public function serialize(): string;
}
// Parameter MUST implement BOTH interfaces
function process(Countable&Serializable $data): string
{
return "Count: {$data->count()}, Serialized: {$data->serialize()}";
}
// DNF Types — Disjunctive Normal Form (PHP 8.2+)
// Combine union and intersection
function handle((Countable&Serializable)|null $data): void
{
// $data implements both OR is null
if ($data === null) {
return;
}
echo $data->count();
}
Запомни: Intersection types (
A&B) — параметр должен реализовать ВСЕ типы. Union types (A|B) — параметр может быть ЛЮБЫМ из типов. DNF types ((A&B)|null) — комбинация обоих (PHP 8.2+).
Readonly свойства (PHP 8.1+)
<?php
declare(strict_types=1);
class Invoice
{
public function __construct(
public readonly string $number,
public readonly float $amount,
public readonly DateTimeImmutable $createdAt,
) {
}
}
$invoice = new Invoice('INV-001', 150.00, new DateTimeImmutable());
echo $invoice->number; // INV-001
// Cannot modify readonly property after initialization
// $invoice->number = 'INV-002'; // Error!
// Readonly properties CAN only be set in constructor or declaration
class Settings
{
public readonly string $theme;
public function __construct(string $theme)
{
$this->theme = $theme; // OK — first assignment
// $this->theme = 'dark'; // Error — already initialized!
}
}
Readonly классы (PHP 8.2+)
<?php
declare(strict_types=1);
// ALL properties are implicitly readonly
readonly class Money
{
public function __construct(
public float $amount,
public string $currency,
) {
}
public function add(Money $other): self
{
if ($this->currency !== $other->currency) {
throw new InvalidArgumentException('Currency mismatch');
}
return new self($this->amount + $other->amount, $this->currency);
}
}
$a = new Money(10.00, 'USD');
$b = new Money(5.00, 'USD');
$c = $a->add($b);
echo $c->amount; // 15.0
// Cannot add non-readonly properties to readonly class
// readonly class Broken {
// public string $mutable; // Error! Must be readonly in readonly class
// }
Ловушка экзамена: В
readonlyклассе ВСЕ свойства автоматически readonly. Нельзя объявить не-readonly свойство.readonlyработает только с типизированными свойствами. Нельзя объявитьreadonlyсвойство без типа.
Nullable типы
<?php
declare(strict_types=1);
class UserService
{
// ?Type syntax (PHP 7.1+)
public function find(int $id): ?User
{
return $id > 0 ? new User($id) : null;
}
// Same as int|null (PHP 8.0+)
public function getAge(int $userId): int|null
{
return $this->find($userId)?->age;
}
// Nullable parameter
public function setName(?string $name): void
{
// $name can be string or null
}
// Default null (implicitly nullable before PHP 8.4)
public function setEmail(string $email = null): void
{
// Deprecated implicit nullable in PHP 8.4!
// Use: ?string $email = null
}
}
Ловушка экзамена: В PHP 8.4 неявная nullable (
string $param = null) помечена как deprecated. Используйте явную:?string $param = null. На экзамене могут проверить знание этого изменения.
Nullsafe оператор (PHP 8.0+)
<?php
declare(strict_types=1);
class Address
{
public function __construct(
public readonly string $city,
public readonly ?string $zip = null,
) {
}
}
class User
{
public function __construct(
public readonly string $name,
public readonly ?Address $address = null,
) {
}
}
$user = new User('Alice');
// Without nullsafe: verbose null checking
$zip = $user->address !== null ? $user->address->zip : null;
// With nullsafe operator
$zip = $user->address?->zip; // null (short-circuits)
// Chaining
$result = $user->address?->zip?->trim(); // null
// With method calls
$length = $user->address?->city?->length(); // Error! string has no length()
// But:
$upper = $user->address?->city;
$upper = $upper !== null ? strtoupper($upper) : null;