Приведи пример инкапсуляции из жизни.

«Приведи пример инкапсуляции из жизни.» — вопрос из категории ООП, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Инкапсуляция — это механизм сокрытия внутреннего состояния и реализации объекта, предоставление доступа к нему только через строго определенный публичный интерфейс (методы).

Жизненная аналогия: Банкомат. Пользователь взаимодействует с ним через простой интерфейс: вставляет карту, вводит PIN, выбирает операцию (получить деньги, посмотреть баланс). Внутри банкомата скрыта сложная логика: проверка PIN-кода с сервером банка, подсчет купюр, ведение журнала операций. Пользователь не имеет прямого доступа к этим внутренним механизмам — они инкапсулированы.

Технический пример на PHP: Рассмотрим класс BankAccount, который инкапсулирует логику работы со счетом.

class BankAccount
{
    // Внутреннее состояние (private) - скрыто от внешнего мира
    private float $balance = 0.0;
    private string $accountNumber;
    private array $transactionHistory = [];

    // Конструктор — часть публичного интерфейса для инициализации
    public function __construct(string $accountNumber)
    {
        $this->accountNumber = $accountNumber;
    }

    // Публичные методы — единственный способ взаимодействия
    public function deposit(float $amount): void
    {
        if ($amount <= 0) {
            throw new InvalidArgumentException('Deposit amount must be positive');
        }
        $this->balance += $amount;
        $this->logTransaction('DEPOSIT', $amount);
    }

    public function withdraw(float $amount): float
    {
        if ($amount <= 0) {
            throw new InvalidArgumentException('Withdrawal amount must be positive');
        }
        if ($amount > $this->balance) {
            throw new RuntimeException('Insufficient funds');
        }
        $this->balance -= $amount;
        $this->logTransaction('WITHDRAWAL', $amount);
        return $amount;
    }

    public function getBalance(): float
    {
        return $this->balance; // Возвращаем копию, а не ссылку на само свойство
    }

    public function getAccountNumber(): string
    {
        return $this->accountNumber;
    }

    public function getLastTransactions(int $limit = 5): array
    {
        return array_slice($this->transactionHistory, -$limit);
    }

    // Приватный метод для внутренней логики — скрыт от внешнего использования
    private function logTransaction(string $type, float $amount): void
    {
        $this->transactionHistory[] = [
            'type' => $type,
            'amount' => $amount,
            'balance_after' => $this->balance,
            'date' => date('Y-m-d H:i:s')
        ];
    }
}

// Использование
$account = new BankAccount('ACC123456');
$account->deposit(1000.0);
$account->withdraw(200.0);

echo $account->getBalance(); // 800.0
// echo $account->balance; // Фатальная ошибка! Свойство private.
// $account->logTransaction(...); // Ошибка! Метод private.

Преимущества такого подхода:

  1. Защита данных: Невозможно напрямую изменить $balance в обход бизнес-правил (проверка на положительность суммы, достаточность средств).
  2. Гибкость: Внутреннюю реализацию (например, способ хранения истории операций) можно изменить, не ломая внешний код, который использует только публичные методы.
  3. Упрощение использования: Клиентскому коду не нужно знать сложности валидации и логирования — он просто вызывает deposit() или withdraw().