Классы в PHP: разбор синтаксиса на живом примере корзины
Что такое класс, свойство, метод, конструктор и видимость в PHP 8.x — на примере корзины интернет-магазина, которую можно собрать и запустить у себя.

К концу этого разбора у вас будет рабочий класс корзины интернет-магазина: он хранит товары, считает сумму и умеет применять скидку. Всё на PHP 8.x, без фреймворков, запускается одним файлом через php cart.php. Разбор для того, кто уже пишет процедурные скрипты на PHP, но ещё не понимает, зачем оборачивать их в классы и что означают слова public, private, __construct.
Проверьте перед началом: PHP версии 8.0 или выше (php -v в терминале). Часть синтаксиса ниже — например, продвижение свойств в конструкторе и типизированные свойства — работает только с 8.0. На PHP 7.4 код придётся переписывать, поэтому если версия старше, начните с обновления.
Что такое класс и зачем он нужен
Класс — это описание того, из чего состоит объект и что он умеет. Данные внутри называются свойствами (поля, переменные объекта), действия — методами (функции, привязанные к объекту). Сам объект создаётся из класса оператором new.
Разница с процедурным кодом простая. Без класса корзина живёт в глобальном массиве, а функции addToCart($cart, $item) и getTotal($cart) таскают этот массив туда-сюда. С классом данные и функции лежат вместе, и снаружи не нужно знать, как именно устроено хранение.
Класс отвечает на два вопроса сразу: что объект знает о себе и что с ним можно сделать. Всё, что не должно быть видно снаружи, прячется внутрь — и это не формальность, а защита от чужих ошибок.
Первый рабочий класс
Соберём корзину пошагово. Начнём с пустого класса и добавим свойства.
<?php
// cart.php — PHP 8.x
class Cart
{
// Свойство: массив товаров. private — снаружи не трогать напрямую
private array $items = [];
}
$cart = new Cart();
var_dump($cart);
Запустите php cart.php. Вы увидите объект Cart с пустым массивом items. Пока он ничего не умеет — добавим методы.
Методы: то, что объект делает
<?php
class Cart
{
private array $items = [];
// Добавить товар. $this — ссылка на текущий объект
public function addItem(string $name, float $price, int $qty = 1): void
{
$this->items[] = [
'name' => $name,
'price' => $price,
'qty' => $qty,
];
}
// Посчитать сумму по всем позициям
public function getTotal(): float
{
$total = 0.0;
foreach ($this->items as $item) {
$total += $item['price'] * $item['qty'];
}
return $total;
}
}
$cart = new Cart();
$cart->addItem('Клавиатура', 3500.0, 1);
$cart->addItem('Мышь', 1200.0, 2);
echo $cart->getTotal(); // 5900
Ключевое здесь — $this. Внутри метода это ссылка на конкретный объект, у которого метод вызвали. Если создать две корзины, у каждой будет свой $items, и $this в методах разведёт их автоматически.
Видимость: public, private, protected
Перед свойством или методом стоит модификатор доступа. Он решает, кто имеет право обращаться к этому члену класса.
| Модификатор | Кто видит | Когда применять |
|---|---|---|
public | кто угодно снаружи | методы, которыми пользуются извне: addItem, getTotal |
private | только сам класс | внутренние данные и вспомогательные методы |
protected | сам класс и наследники | когда планируете наследование и хотите открыть доступ дочерним классам |
Почему $items сделали private: если бы он был public, любой код снаружи мог бы записать туда что угодно — строку вместо массива, товар без цены. Прятать данные и давать доступ только через методы — это не бюрократия, а способ гарантировать, что внутри корзины всегда корректное состояние.
Конструктор: начальное состояние объекта
Метод __construct вызывается автоматически при new. В нём задают то, что объект должен знать с рождения. Например, валюту и ставку скидки для конкретного покупателя.
В PHP 8.0 появилось продвижение свойств конструктора: параметр с модификатором доступа сразу становится свойством, без отдельного объявления и ручного присваивания.
<?php
class Cart
{
private array $items = [];
// Свойства $currency и $discountRate объявляются прямо здесь
public function __construct(
private string $currency = 'RUB',
private float $discountRate = 0.0,
) {}
public function addItem(string $name, float $price, int $qty = 1): void
{
$this->items[] = compact('name', 'price', 'qty');
}
public function getTotal(): float
{
$sum = 0.0;
foreach ($this->items as $item) {
$sum += $item['price'] * $item['qty'];
}
// Применяем скидку, если она задана
return $sum * (1 - $this->discountRate);
}
public function getCurrency(): string
{
return $this->currency;
}
}
$cart = new Cart(discountRate: 0.1); // скидка 10%
$cart->addItem('Клавиатура', 3500.0);
$cart->addItem('Мышь', 1200.0, 2);
printf('%.2f %s', $cart->getTotal(), $cart->getCurrency());
// 5310.00 RUB
До 8.0 этот же конструктор занимал вдвое больше строк: сначала объявляешь private float $discountRate;, потом внутри пишешь $this->discountRate = $discountRate;. Продвижение убирает эту рутину. Если вы на 7.4 — используйте старую запись, короткая форма не заработает.
Собираем всё вместе
Финальный вариант класса добавляет проверку на пустую цещу и метод подсчёта позиций. Это цельный файл — скопируйте и запустите.
<?php
// cart.php — PHP 8.x, запуск: php cart.php
class Cart
{
private array $items = [];
public function __construct(
private string $currency = 'RUB',
private float $discountRate = 0.0,
) {
// Скидка вне диапазона 0..1 — ошибка данных, а не рабочая ситуация
if ($discountRate < 0 || $discountRate > 1) {
throw new InvalidArgumentException('Скидка должна быть от 0 до 1');
}
}
public function addItem(string $name, float $price, int $qty = 1): void
{
if ($price < 0 || $qty < 1) {
throw new InvalidArgumentException('Некорректная цена или количество');
}
$this->items[] = compact('name', 'price', 'qty');
}
public function countItems(): int
{
return array_sum(array_column($this->items, 'qty'));
}
public function getTotal(): float
{
$sum = array_reduce(
$this->items,
fn(float $acc, array $item) => $acc + $item['price'] * $item['qty'],
0.0
);
return round($sum * (1 - $this->discountRate), 2);
}
}
$cart = new Cart(discountRate: 0.15);
$cart->addItem('Монитор', 18000.0);
$cart->addItem('Кабель HDMI', 700.0, 3);
printf("Позиций: %d, к оплате: %.2f\n", $cart->countItems(), $cart->getTotal());
// Позиций: 4, к оплате: 17085.00
Обратите внимание на throw new InvalidArgumentException: класс сам следит за тем, чтобы в него не попали кривые данные. Это и есть польза инкапсуляции — состояние объекта нельзя испортить снаружи в обход проверок.
Если не получилось
- Parse error: syntax error, unexpected token "private" — продвижение свойств в конструкторе не поддерживается вашей версией PHP. Проверьте
php -v: нужна 8.0+. На 7.4 объявляйте свойства отдельно. - Uncaught Error: Cannot access private property Cart::$items — вы пытаетесь обратиться к
$cart->itemsснаружи класса. Так и задумано: добавьте публичный метод-геттер или работайте черезaddItem. - Fatal error: Uncaught Error: Call to undefined method — опечатка в имени метода или метод объявлен, но файл не сохранён. Имена методов в PHP чувствительны к контексту вызова, но не к регистру —
getTotalиgettotalвызовут один метод. - TypeError: ...must be of type float, string given — типизированные свойства и параметры отвергают неподходящий тип. Передавайте
3500.0, а не'3500', либо уберите строгую типизацию из объявления.
Что делать дальше
Класс корзины работает — дальше есть три направления, каждое тянет на отдельный разбор:
- Наследование и интерфейсы — когда появится вторая корзина с другой логикой скидок, вынесите общее в базовый класс или интерфейс. Здесь мы этого не касались.
- Статические свойства и методы (
static) — для данных, общих на весь класс, а не на объект. - Магические методы (
__get,__toStringи другие) — для нестандартного поведения объекта.
Следующий практический шаг: перепишите любой свой процедурный скрипт с глобальным массивом в класс. Ориентир — если функции постоянно принимают и возвращают один и тот же массив данных, это кандидат в класс. Проверять синтаксис версии удобно в официальной документации по классам.
Репетитор 1—11 класс и ВУЗ: Математика и физика методом наведения на мысль, помощь с ДЗ.
Спросить за 8 ₽Источники: PHP Manual — Classes and Objects, PHP Manual — Constructor Promotion
Частые вопросы
У меня PHP 7.4, код с продвижением свойств не работает — что делать?
В чём разница между свойством и переменной?
Зачем делать свойства private, если public проще?
Что будет, если не написать конструктор?
Можно ли создать несколько объектов одного класса, и не будут ли они мешать друг другу?
Почему getTotal возвращает round, а не точную сумму?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.