В общепринятом ООП есть один термин, которым любят пугать новичков. Имя ему — инкапсуляция.
В первой части этого курса мы строили абстракции, используя обычные функции с применением подхода data hiding.
<?php
$point = makeDecartPoint(3, 4);
getX($point); // 3
getY($point); // 4
В объектно-ориентированном подходе функции объединяются с данными и описываются вместе внутри класса (в классово-ориентированных языках). Инкапсуляция — механизм, позволяющий описывать данные и функции, оперирующие ими, в рамках одной языковой конструкции. В случае PHP такой конструкцией является класс.
Мы уже начали так делать, когда знакомились с конструктором. Такие функции принято именовать методами, так как они связаны с объектом, на котором вызываются. Визуально вызов метода выглядит как обращение к свойству и его вызов.
<?php
$point = new Point(3, 4);
$point->getX(); // 3
$point->getY(); // 4
Вызов метода не требует передачи объекта в аргументах, потому что метод вызывается на объекте и имеет к нему доступ через переменную $this
.
<?php
class Point
{
public $x;
public $y;
public function __construct($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function getX()
{
return $this->x;
}
public function getY()
{
return $this->y;
}
}
Методы, которые извлекают составные части объекта, принято называть геттерами (getters), а методы, изменяющие составные части — сеттерами (setters). Как правило, геттеры и сеттеры один в один отображаются на конкретные свойства внутри объекта. Технически методы — обычные функции, за исключением доступа к $this
и способа вызова.
<?php
class Point
{
public $x;
public $y;
public function __construct($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function getX()
{
return $this->x;
}
public function getY()
{
return $this->y;
}
public function setX($x)
{
$this->x = $x;
}
public function setY($y)
{
$this->y = $y;
}
}
$point = new Point(5, 10);
$point->setX(100);
print_r($point->getX()); // => 100
Сеттеры в примере выше показаны только для демонстрации. В реальном коде точка почти наверняка будет неизменяемым объектом.
Но геттеры и сеттеры — не единственные типы функций, которые позволяют описывать класс. В принципе, всё, что мы описывали, работая без классов, с таким же успехом описывается и с классами.
Реализация без классов:
<?php
function distanceTo($point1, $point2)
{
$squareOfX = (getX($point1) — getX($point2)) ** 2;
$squareOfY = (getY($point1) — getY($point2)) ** 2;
return sqrt($squareOfY + $squareOfX);
}
Реализация в классе:
<?php
class Point
{
...
/*
* Расчет по теореме Пифагора связи между
* сторонами прямоугольного треугольника с^2 = a^2 + b^2
*/
public function distanceTo($point)
{
$squareOfX = ($this->getX() — $point->getX()) ** 2;
$squareOfY = ($this->getY() — $point->getY()) ** 2;
return sqrt($squareOfY + $squareOfX);
}
}
$point1 = new Point(0, 0);
$point2 = new Point(3, 4);
print_r($point1->distanceTo($point2)); // => 5
print_r($point2->distanceTo($point1)); // => 5
Данная операция обладает свойством коммутативности: результат вычисления не зависит от того, в каком порядке идут аргументы. Соответственно, при использовании методов, можно вызывать distanceTo
как на одном объекте, так и на другом.
Нередко методы выполняют не только вычисления, но и возвращают новые объекты. Например, так произойдёт при вычислении симметричной точки.
<?php
class Point
{
// ...
public function getSymmetricalPoint()
{
// Можно выполнять промежуточное создание переменной, а можно возвращать сразу
return new Point(-$this->getX(), -$this->getY());
}
}
$point = new Point(3, 8);
$point->getSymmetricalPoint(); // => (-3, -8)
Выше мы рассмотрели техническую сторону вопроса, оставив за кадром описание преимуществ и недостатков такого подхода, а также связанные темы, например, data hiding или полиморфизм. Их описание довольно обширно и практически бесполезно без хотя бы минимального опыта использования. О том, что даёт или забирает инкапсуляция, мы поговорим на протяжении ближайших уроков. Отдельного обсуждения заслуживает вопрос о способе хранения методов — где они находятся физически (внутри объекта или нет?). С ним мы разберёмся в уроках, посвящённых полиморфизму и динамической диспетчеризации.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.