PHP: Что такое Класс

Источник: «What Is a PHP Class?»
Как новичок в программировании, особенно в PHP, вы, возможно, слышали термины классы или объекты. Что такое PHP класс?

Во-первых, мы предполагаем, что вы знаете, что такое PHP функция.

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

PHP класс и, в более общем смысле, объектно-ориентированное программирование предоставляют дополнительные подходы к повторному использованию и могут использоваться для различных целей:

PHP класс — это план, определяющий сочетание свойств и поведения, который действует как шаблон для того, что называется объектами или экземплярами класса.

Хотя они могут звучать устрашающе, по сути, синтаксически они являются лишь формой объявления:

class WheeledVehicle
{
}

Мы можем создать экземпляр колёсного транспорта — WheeledVehicle, используя ключевое слово new:

$car = new WheeledVehicle();

Сам по себе такой пустой класс даёт нам только одно: тип. Вы уже знаете ряд встроенных типов: null, boolean, string, integer, float, и array. В PHP начиная с версии 7.4 мы можем указать любой из них. Например, если мы хотим разрешить только string в качестве аргумента функции и разрешить возврат из неё только string, мы можем задать это следующим способом:

function transform(string $message): string

PHP классы позволяют определять дополнительные типы для языка PHP. Возвращаясь к нашему примеру, $car теперь является экземпляром WheeledVehicle. Если бы хотели, чтобы наша функция transform() разрешала только экземпляры WheeledVehicle, мы могли бы написать её следующим образом:

function transform(WheeledVehicle $message): string

Если попытаться передать что-либо, кроме экземпляра WheeledVehicle, код вызовет ошибку!

PHP Свойства Класса

Есть много видов колёсного транспорта: одноколёсные велосипеды, велосипеды, мотоциклы, трёхколёсные велосипеды, фургоны, тележки, автомобили, грузовики, фуры и многое другое. Они отличаются друг от друга разнообразием свойств и поведения. Сначала поговорим о свойствах.

Свойства PHP класса являются частью состояния объекта и представляют собой элемент, который можно повторно использовать. И на который можно ссылаться внутри класса и, в зависимости от того, как оно определено, потребителями экземпляра класса. Свойство может быть:

Давайте расширим класс WheeledVehicle добавив некоторые свойства:

class WheeledVehicle
{
int $wheelCount;
bool $usesFuel;
bool $selfPropelled;
float $weight;
}

Мы определяем количество колёс ($wheelCount), использует ли он топливо ($usesFuel), является ли самоходным ($selfPropelled) и вес ($weight). Для каждого свойства мы задали допустимый тип, чтобы всегда знать, что получим от свойства, а также какие значения будут приняты.

Подсказка типов появилась в PHP 7.4, в предыдущих версиях они были недоступны. Вместо них использовалось ключевое слово var (в настоящее время устарело) или оператор видимости. Для упрощения примеров объявления указываются только с типом.

Теперь мы можем немного лучше определить экземпляр $car:

$car->wheelCount    = 4;
$car->usesFuel = true;
$car->selfPropelled = true;
$car->weight = 2200;

Что это за обозначение ->? И почему свойства не указываются с помощью $?

Синтаксис, используемый для ссылки на свойство экземпляра, заключается в использовании оператора -> между переменной экземпляра ($car) и именем свойства. Мы можем присвоить значение с помощью оператора присваивания = или получить значение, просто обратившись к нему (например, $car->weight).

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

PHP Методы Класса

Хорошо, что у WheeledVehicle теперь есть свойства, но как насчёт поведения?

Мы можем задать поведение, определив методы класса. Метод — это функция, ограниченная экземпляром класса. Это означает, что он может получить доступ к значениям свойств, связанных с экземпляром класса. В нашем примере выше $car является экземпляром класса WheeledVehicle, и к назначенным нами значениям можно получить доступ в определённых им методах.

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

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

Написание PHP Метода Класса

Давайте напишем метод сравнивающий количество колёс в экземпляре с другим экземпляром. Идея будет заключаться в том, что мы могли бы использовать этот метод для сортировки экземпляров WheeledVehicle по количеству колёс, которые у них есть. Большинство функций сортировки возвращают -1, если левый элемент меньше правого, 0, если они равны, и 1, если левый элемент больше правого. Начиная с PHP 7.4 для таких сравнений существует специальный оператор, оператор spaceship, <=>. Для наших целей мы будем считать текущий экземпляр левой частью операции.

Внутри класса определим метод:

class WheeledVehicle
{
int $wheelCount;
bool $usesFuel;
bool $selfPropelled;
float $weight;

public function compareWheelCount(WheeledVehicle $comparison): int
{
return $this->wheelCount <=> $comparison->wheelCount;
}
}

Что такое $this? В синтаксисе PHP, $this является текущим экземпляром класса и используется внутри для ссылки на свойства экземпляра, а также для вызова его собственных методов. Здесь мы сравниваем $wheelCount текущего экземпляра с другим предоставленным нам экземпляром. $this->wheelCount даст значение, присвоенное текущему экземпляру. Для нашего определения $car ранее это значение будет равно 4.

Ключевое слово public используется для определения видимости метода, то есть, по сути, того, кто может его вызвать и где он может быть вызван. Методы по умолчанию имеют видимость public, но лучше всего явно определить видимость.

Если бы у нас было несколько экземпляров WheeledVehicle, мы могли бы отсортировать их массив следующим образом:

usort($wheeledVehicles, function ($a, $b) {
return $a->compareWheelCount($b)
});

Начиная с PHP 7.4, вы можете определять стрелочные функции представляющие собой компактный способ определения замыканий, возвращающих результат одного выражения. Вышеупомянутое так же может быть записано:

usort($wheeledVehicles, fn($a, $b) => $a->compareWheelCount($b));

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

Наследование Классов в PHP

Было бы неплохо не задавать все свойства автомобиля. Что, если бы мы могли определить их и при этом иметь понятие колёсное транспортное средство?

Классы позволяют делать это через расширение класса. Мы собираемся создать класс Car, расширяющий WheeledVehicle, и заранее определить некоторые из свойств:

class Car extends WheeledVehicle
{
int $wheelCount = 4;
bool $usesFuel = true;
bool $selfPropelled = true;
}

Теперь мы можем определить машину следующим образом:

$sedan = new Car();
$sedan->weight = 2200;

Если бы мы получили доступ к другим свойствам, мы бы обнаружили, что они имеют разумные значения по умолчанию:

if ($sedan->usesFuel && $sedan->selfPropelled) {
printf("Vehicle has %d wheels.\n", $sedan->wheelCount); // "Vehicle has 4 wheels"
}

Ключевое слово extends сообщает PHP, что объявляемый новый класс будет наследоваться от указанного класса. Это означает, что ели мы не переопределим их, новый класс будет иметь те же свойства и поведение.

В классе Car мы переопределили определения $wheelCount, $usesFuel и $selfPropelled предоставив значения по умолчанию. Это означает, что нам нужно указать вес ($weight) только после того, как мы создали экземпляр. Мы также можем вызвать метод compareWheelCount() который определили в WheeledVehicle!

Что особенно интересно, так это то, что, поскольку Car расширяет WheeledVehicle, он имеет тот же тип. Вы можете передать свой $car функции или методу, для которых требуется тип WheeledVehicle! По сути, наследование в PHP представляет собой отношения является: Car является WheeledVehicle.

И наоборот, если мы укажем подсказку типа Car, поскольку он более специфичен, чем WheeledVehicle, экземпляр WheeledVehicle не является Car и не будет соответствовать подсказке типа.

$bike  = new WheeledVehicle();
$sedan = new Car();

echo $bike instanceof WheeledVehicle ? 'TRUE' : 'FALSE'; // TRUE
echo $bike instanceof Car ? 'TRUE' : 'FALSE'; // FALSE
echo $sedan instanceof WheeledVehicle ? 'TRUE' : 'FALSE'; // TRUE
echo $sedan instanceof Car ? 'TRUE' : 'FALSE'; // TRUE

Конструкторы PHP Классов

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

Конструктор — это метод вызываемый при создании нового экземпляра класса. Он может принимать аргументы, но не должен определять возвращаемое значение. Конструкторы обычно используются для инициализации свойств класса на основе предоставленных им аргументов. В PHP конструктор должен называться __construct() (префикс __ указывать на зарезервированные магические методы, используемые языком для определённых действий).

Давайте напишем конструктор для Car принимающий значение $wieght:

class Car extends WheeledVehicle
{
int $wheelCount = 4;
bool $usesFuel = true;
bool $selfPropelled = true;

public function __construct(float $weight)
{
$this->weight = $weight;
}
}

Конструктор принимает аргумент $weight, а затем присваивает его свойству. Но мы не определяли это свойство! Почему? Потому что оно уже определено в родительском классе WheeledVehicle.

Теперь мы можем создать седан ($sedan) намного проще:

$sedan = new Car(2200);

Заключение

PHP Классы — способ определения новых типов языка, предоставляющий шаблон для данных и поведения, которые они инкапсулируют. Кроме того, они предоставляют функциональные возможности для создания таксономий типов посредством наследования.

Дополнительные материалы

Предыдущая Статья

PHP: Что такое функция

Следующая Статья

PHP: Что такое Интерфейс