Свойства и методы
Свойства
Хранят данные объекта.
class User
{
public string $name;
private int $age;
protected ?string $email = null;
}
Каждый объект имеет свои значения.
Типизация
Обязательна (PHP 7.4+):
public string $name;
public int $age;
public ?string $email = null;
public array $roles = [];
public User $friend; // класс
public Status $status; // enum
public mixed $data; // mixed
Union:
public int|string $id;
readonly:
public readonly string $email;
Инициализация
По умолчанию нельзя для типизированных свойств без ?:
class Foo
{
public string $name; // uninitialized
}
$foo = new Foo();
echo $foo->name; // Error: must not be accessed before initialization
Решение:
class Foo
{
public string $name = ''; // дефолт
public ?string $bio = null; // nullable
public string $email; // инициализировать в конструкторе
public function __construct()
{
$this->email = '';
}
}
Методы
Функции класса:
class Calculator
{
public function add(int $a, int $b): int
{
return $a + $b;
}
private function log(string $msg): void
{
error_log($msg);
}
}
Видимость методов — те же правила.
Геттеры и сеттеры
Классический паттерн:
class User
{
private string $name;
private int $age;
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getAge(): int
{
return $this->age;
}
public function setAge(int $age): void
{
if ($age < 0 || $age > 150) {
throw new InvalidArgumentException('Некорректный возраст');
}
$this->age = $age;
}
}
Плюс: контроль над чтением/записью.
Минус: много кода.
Альтернатива — property hooks (PHP 8.4)
class User
{
public string $name {
get => strtoupper($this->name);
set => trim($value);
}
}
Пока ново. Используй геттеры/сеттеры.
Публичные свойства — когда ок
Простые DTO:
final readonly class CreateUserDto
{
public function __construct(
public string $name,
public string $email,
) {}
}
Здесь геттеры не нужны — readonly гарантирует неизменность.
Fluent interface
Цепочка вызовов:
class QueryBuilder
{
private array $wheres = [];
private ?int $limit = null;
public function where(string $field, mixed $value): static
{
$this->wheres[] = [$field, $value];
return $this;
}
public function limit(int $n): static
{
$this->limit = $n;
return $this;
}
public function toSql(): string
{
// ...
}
}
$sql = (new QueryBuilder())
->where('age', '> 18')
->where('active', true)
->limit(10)
->toSql();
return $this — для цепочки.
static — правильно работает с наследованием.
Статические методы
Вызываются без объекта:
class Math
{
public static function sum(int ...$nums): int
{
return array_sum($nums);
}
public static function max(int ...$nums): int
{
return max($nums);
}
}
echo Math::sum(1, 2, 3); // 6
Не имеют $this.
Правило: статика — только для чистых функций, без состояния.
Статические свойства
class Counter
{
private static int $count = 0;
public static function increment(): void
{
self::$count++;
}
}
Одно на класс, не на объект.
⚠️ Осторожно: глобальное состояние, тяжело тестировать.
Константы
class Status
{
public const ACTIVE = 'active';
public const PENDING = 'pending';
}
echo Status::ACTIVE;
В PHP 8.3+ — типизированные:
public const string ACTIVE = 'active';
Enum предпочтительнее для наборов значений.
self vs static vs parent
self — текущий класс:
class Foo
{
public static function create(): self
{
return new self();
}
}
static — вызывающий класс (правильно для наследования):
class Base
{
public static function create(): static
{
return new static();
}
}
class Child extends Base {}
$c = Child::create(); // Child, не Base
parent — родительский класс:
class Child extends Base
{
public function __construct()
{
parent::__construct();
}
}
$this vs self
$this — объект:
$this->name;
$this->method();
self — класс:
self::$staticProp;
self::CONSTANT;
self::staticMethod();
Магические методы
__construct
Конструктор.
__destruct
Деструктор.
__toString
class User
{
public function __construct(private string $name) {}
public function __toString(): string
{
return $this->name;
}
}
$user = new User('Иван');
echo $user; // Иван
__get, __set
Для несуществующих свойств:
class Dynamic
{
private array $data = [];
public function __get(string $name): mixed
{
return $this->data[$name] ?? null;
}
public function __set(string $name, mixed $value): void
{
$this->data[$name] = $value;
}
public function __isset(string $name): bool
{
return isset($this->data[$name]);
}
}
Используется в Eloquent (Laravel), Active Record.
__call
Для несуществующих методов:
class Proxy
{
public function __call(string $name, array $args): mixed
{
return "Метод $name с аргументами " . implode(', ', $args);
}
}
$p = new Proxy();
echo $p->foo(1, 2); // Метод foo с аргументами 1, 2
__invoke
Объект как функция:
class Adder
{
public function __construct(private int $n) {}
public function __invoke(int $x): int
{
return $x + $this->n;
}
}
$add5 = new Adder(5);
echo $add5(10); // 15
Порядок объявления
Соглашение (PSR-12):
- Константы.
- Свойства.
- Конструктор.
- Публичные методы.
- Protected методы.
- Приватные методы.
Практика
<?php
declare(strict_types=1);
final class Money
{
public function __construct(
private int $amount,
private string $currency = 'RUB',
) {
if ($amount < 0) {
throw new InvalidArgumentException('Сумма не может быть отрицательной');
}
}
public function getAmount(): int
{
return $this->amount;
}
public function getCurrency(): string
{
return $this->currency;
}
public function add(Money $other): static
{
if ($this->currency !== $other->currency) {
throw new InvalidArgumentException('Валюты разные');
}
return new static(
$this->amount + $other->amount,
$this->currency,
);
}
public function multiply(int $factor): static
{
return new static($this->amount * $factor, $this->currency);
}
public function format(): string
{
return number_format($this->amount / 100, 2) . ' ' . $this->currency;
}
public function equals(Money $other): bool
{
return $this->amount === $other->amount
&& $this->currency === $other->currency;
}
}
$price = new Money(100000);
$total = $price->multiply(3);
echo $total->format(); // 3000.00 RUB
Итог
- Свойства — данные, методы — поведение.
- Геттеры/сеттеры — инкапсуляция.
- Fluent —
return $thisдля цепочек. - Статика —
self::,static::. - Константы — через
const. - Магические методы —
__toString,__get,__call,__invoke. - Порядок: константы → свойства → конструктор → методы.
Дальше — конструкторы и деструкторы.