Это принцип, согласно которому любой класс и в более широком смысле, любая часть системы должны рассматриваться как "черный ящик", т.е. пользователь объекта или подсистемы должен видеть только контракт (т.е. список декларируемых свойств и методов) и не вникать во внутреннюю реализацию.

У термина существует 2 трактовки:

  1. В объект объединяются и данные и методы для работы с этими данными
  2. Сокрытие внутренней структуры объекта от внешнего мира

Часто приводят в пример инкапсуляции класс, в котором все поля приватные, а доступ к ним осуществляется через геттеры и сеттеры. Но это не является инкапсуляцией, т.к. в итоге состояние объекта доступно вне класса.

Рассмотрим пример неправильного использования инкапсуляции:

В данном случае мы изменяем статус заказа где-то из вне самого класса, по сути никак не скрывая его внутреннее состояние от внешнего мира. Получаем процедурный код, завернутый в классы. С таким же успехом можно просто сделать поля класса публичными и ничего концептуально не поменяется.

<?php
class Order
{
    public const STATUS_OPEN = 'open';
    public const STATUS_PAYED = 'payed';

    private string $status;

    public function getStatus(): string
    {
        return $this->status;
    }

    public function setStatus(string $status): void
    {
        $this->status = $status;
    }

		//...
}

// pay action
$orderId = $request->get('id');

$order = $repository->find($orderId);
if ($order->getStatus() === Order::STATUS_PAYED) {
     throw new OrderDomainException('Order already payed.');
}

$order->setStatus(Order::STATUS_PAYED);
$repository->save($order);

Используя инкапсуляцию более верно, мы можем написать следующий код:

<?php
class Order
{
    private const STATUS_OPEN = 'open';
    private const STATUS_PAYED = 'payed';

    private string $status;

    public function pay(): void
    {
				if ($this->status === self::STATUS_PAYED) {
				     throw new OrderDomainException('Order already payed.');
				}
				
				$this->status = self::STATUS_PAYED;
    }

		public function isPayed(): bool 
		{
				return $this->status === self::STATUS_PAYED;
		}
}

// pay action
$orderId = $request->get('id');

$order = $repository->find($orderId);
$order->pay();
$repository->save($order);

Т.е. мы можем вывести более точную формулировку инкапсуляции - данные объекта должны обрабатываться только там, где они находятся. Тесно связано с паттерном GRASP

Information Expert

Сокрытие информации - в компьютерной науке сокрытие информации - это принцип разделения проектных решений в компьютерной программе, которые с наибольшей вероятностью могут измениться, тем самым защищая другие части программы от обширных модификаций в случае изменения проектного решения. Защита подразумевает обеспечение стабильного интерфейса, который защищает оставшуюся часть программы от реализации (детали, которые с наибольшей вероятностью могут измениться).

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

Пример:

Представим на минутку, что мы оказались в конце позапрошлого века, когда Генри Форд ещё не придумал конвейер, а первые попытки создать автомобиль сталкивались с критикой властей по поводу того, что эти коптящие монстры загрязняют воздух и пугают лошадей. Представим, что для управления первым паровым автомобилем необходимо было знать, как устроен паровой котёл, постоянно подбрасывать уголь, следить за температурой, уровнем воды. При этом для поворота колёс использовать два рычага, каждый из которых поворачивает одно колесо в отдельности. Думаю, можно согласиться с тем, что вождение автомобиля того времени было весьма неудобным и трудным занятием.