Правильно ли получать приватное свойство через геттер?

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

Ответ

Да, это не только правильно, но и является фундаментальным принципом инкапсуляции в ООП. Прямой доступ к приватным свойствам нарушает инкапсуляцию, лишая класс контроля над своими данными.

Почему геттеры (и сеттеры) — это must-have в production-коде:

  1. Контроль над состоянием: Геттер позволяет возвращать не просто сырое значение, а вычисляемое или форматированное. Например, геттер для даты может возвращать ее в определенном часовом поясе.
  2. Ленивая инициализация (lazy load): Вы можете инициализировать тяжелый ресурс только при первом обращении через геттер.
  3. Совместимость и рефакторинг: Внутреннее представление данных можно полностью изменить, оставив публичный API (геттер) неизменным.

Практический пример с логикой в геттере:

class User {
    private DateTimeImmutable $createdAt;
    private ?string $firstName;
    private ?string $lastName;

    public function __construct(string $firstName, string $lastName) {
        $this->createdAt = new DateTimeImmutable('now', new DateTimeZone('UTC'));
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    // Геттер с вычисляемым значением
    public function getFullName(): string {
        return trim($this->firstName . ' ' . $this->lastName);
    }

    // Геттер с форматированием и инвариантом (всегда UTC)
    public function getCreatedAtIso8601(): string {
        return $this->createdAt->format(DateTimeInterface::ATOM); // Всегда в стандартном формате
    }

    // Геттер, который может вернуть null, но мы это явно указываем в типе
    public function getLastName(): ?string {
        return $this->lastName;
    }
}

// Использование
$user = new User('John', 'Doe');
echo $user->getFullName(); // "John Doe"
echo $user->getCreatedAtIso8601(); // "2023-10-27T10:00:00+00:00"
// echo $user->createdAt; // Fatal error: Cannot access private property

Таким образом, геттер — это не просто обертка, а полноценный метод, который является частью контракта класса и может содержать важную логику.