Сокрытие данных
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 41 из 91.
Скрытие информации — это принцип, лежащий в основе инкапсуляции: идея о том, что класс должен предоставлять только то, что необходимо, и скрывать детали своей внутренней реализации. В то время как модификаторы доступа и геттеры/сеттеры являются инструментами, скрытие информации — это философия проектирования, которая определяет, как вы их используете.
Цель состоит в том, чтобы создать четкую границу между тем, что делает класс (его публичный интерфейс), и тем, как он это делает (его внутренняя реализация). Такое разделение означает, что вы можете изменять внутренние механизмы работы, не затрагивая код, который использует этот класс:
<?php
class Temperature {
private float $celsius;
public function setCelsius(float $value): void {
$this->celsius = $value;
}
public function getCelsius(): float {
return $this->celsius;
}
public function getFahrenheit(): float {
return ($this->celsius * 9/5) + 32;
}
}
$temp = new Temperature();
$temp->setCelsius(25);
echo $temp->getCelsius() . "C = " . $temp->getFahrenheit() . "F";
Вывод:
25C = 77FКласс хранит температуру внутри в градусах Цельсия, но пользователям не обязательно об этом знать. Позже вы могли бы изменить внутреннее хранилище на Фаренгейт или Кельвин, и пока публичные методы работают так же, никакой внешний код не сломается.
Ключевой момент: Скрытие информации защищает ваш код от изменений. Скрывайте детали реализации, предоставляйте только стабильные интерфейсы, и ваши классы станет легче поддерживать и изменять со временем.
Задание
ЛегкоДавайте создадим конвертер валют, который демонстрирует сокрытие информации в действии. Вы создадите класс, который хранит деньги внутри в одной валюте, но может плавно конвертировать их в несколько валют и обратно — при этом внешний код никогда не узнает, как на самом деле хранятся данные.
Вы организуете свой код в двух файлах:
Money.php— Создайте классMoney, который внутренне хранит все суммы в центах (как целое число), чтобы избежать проблем с точностью чисел с плавающей запятой. Эта деталь реализации должна быть полностью скрыта от пользователей класса. Класс должен предоставлять:- Приватное свойство для хранения суммы в центах
setDollars(float $amount)— принимает сумму в долларах и сохраняет ее внутри как центыgetDollars()— возвращает сумму в долларах (float, 2 знака после запятой)setEuros(float $amount)— принимает евро и конвертирует в центы, используя курс: 1 EUR = 1.10 USDgetEuros()— возвращает сумму, конвертированную в евро (float, 2 знака после запятой)getInternalValue()— возвращает необработанное значение в центах (integer) для целей отладки
main.php— Подключите файл Money. Вы получите два входных значения: сумму в долларах и сумму в евро. Создайте экземплярMoney. Сначала установите сумму в долларах (преобразованную во float) и выведите три строки: значение в долларах, эквивалент в евро и внутреннее значение в центах. Затем установите сумму в евро (преобразованную во float) и снова выведите те же три значения.
Прелесть такого дизайна заключается в том, что внешний код работает со знакомыми значениями долларов и евро, совершенно не подозревая, что внутри все хранится в центах. Позже вы могли бы изменить внутреннее хранилище, чтобы использовать другую базовую валюту или другую стратегию точности, и пока публичные методы продолжают работать правильно, никакой внешний код не придется менять.
Форматируйте все выходные данные в долларах и евро ровно до 2 знаков после запятой. Каждое значение должно быть напечатано на отдельной строке, в итоге должно получиться шесть строк вывода.
Шпаргалка
Скрытие информации — это принцип, лежащий в основе инкапсуляции: предоставление только необходимого при скрытии деталей внутренней реализации. Это создает четкую границу между тем, что делает класс (публичный интерфейс), и тем, как он это делает (внутренняя реализация).
Пример скрытия информации с классом Temperature:
<?php
class Temperature {
private float $celsius;
public function setCelsius(float $value): void {
$this->celsius = $value;
}
public function getCelsius(): float {
return $this->celsius;
}
public function getFahrenheit(): float {
return ($this->celsius * 9/5) + 32;
}
}
$temp = new Temperature();
$temp->setCelsius(25);
echo $temp->getCelsius() . "C = " . $temp->getFahrenheit() . "F";
// Вывод: 25C = 77F
Класс хранит температуру внутри в градусах Цельсия, но пользователям не обязательно об этом знать. Внутреннее хранилище можно изменить на Фаренгейт или Кельвин, не нарушая работу внешнего кода, пока публичные методы продолжают работать так же.
Основные преимущества: Скрытие информации защищает код от изменений. Скрывая детали реализации и предоставляя только стабильные интерфейсы, классы становятся проще в обслуживании и модификации с течением времени.
Попробуйте сами
<?php
require_once 'Money.php';
// Чтение входных данных
$dollarAmount = floatval(trim(fgets(STDIN)));
$euroAmount = floatval(trim(fgets(STDIN)));
// TODO: Создать экземпляр Money
// TODO: Установить сумму в долларах и вывести:
// - Значение в долларах (2 знака после запятой)
// - Эквивалент в евро (2 знака после запятой)
// - Внутреннее значение в центах (целое число)
// TODO: Установить сумму в евро и вывести:
// - Значение в долларах (2 знака после запятой)
// - Эквивалент в евро (2 знака после запятой)
// - Внутреннее значение в центах (целое число)
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Итоги — Простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыИтоги — Иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateПодробный разбор модификаторов доступаГеттеры и сеттерыСокрытие данныхConstructor Promotion (8.0)Итоги — Система учета студентов10Продвинутые концепции ООП
Композиция против наследованияВнедрение зависимостейАнонимные классыПеречисления (PHP 8.1)Файберы (PHP 8.1)Глубокое погружение в клонирование объектовГенераторы и итераторы13Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий2Пространства имен и автозагрузка
Введение в пространства именКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerИтоги: структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс против абстрактного классаType Hinting с интерфейсамиИтоги — Калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeИтоги — Кастомная коллекция11Система типов и обработка ошибок
Объявление типовNullable-типыТипы объединения и пересеченияКлассы исключенийИерархия пользовательских исключенийTry, Catch, FinallyИтоги — Валидатор форм14Проект: Управление библиотекой
Обзор проектаКлассы Book и User3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищенные свойстваСвойства Readonly (PHP 8.1)Итоги — Менеджер банковского счета6Полиморфизм
Снова о переопределении методовПолиморфизм через интерфейсыType Hinting и Union TypesПозднее статическое связываниеИтоги — Payment Processor9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy