Использование трейтов в PHP
Минимизация дублирования кода за счет лучшей организации и повторного использования является важной целью объектно-ориентированного программирования. Но в PHP иногда возникают сложности - из-за ограничений используемой модели единого наследования у вас могут быть некоторые методы, которые вы хотели бы использовать в нескольких классах, но они могут плохо вписываться в иерархию наследования.
Языки, подобные C++ и Python, позволяют нам наследоваться от нескольких классов, которые в какой-то мере решают эту проблему, а mixins в Ruby позволяет смешивать функциональность одного или нескольких классов без использования наследования. Но множественное наследование имеет свои проблемы.
В этой статье я расскажу о трейтах в php - новую функциональность , представленную в PHP 5.4 для решения таких проблем. Понятие самих трейтов не является чем-то новым для программирования и используется в других языках, таких как Scala и Perl. Они позволяют нам повторно использовать код через независимые классы в разных иерархиях.
Что представляет трейт
Трейт похож на абстрактный класс, который не может быть создан сам по себе (хотя чаще он сравнивается с интерфейсом). Документация PHP определяет трейты следующим образом:
Трейты - это механизм повторного использования кода в отдельных языках, таких как PHP. Трейт предназначен для преодоления некоторых ограничений одиночного наследования, позволяя разработчику свободно использовать множество методов в нескольких независимых классах, находящихся в разных иерархиях.
Рассмотрим пример:
<?php
class DbReader extends Mysqli {}
class FileReader extends SplFileObject {}
?>
Все будет хорошо до тех пор, пока нам не станет необходимо использовать общую функциональность для этих классов. Конечно, мы можем написать один и тот же кусок кода два раза, но это отнюдь не хорошая практика.
Допустим, оба класса должны быть синглтонами. Поскольку PHP не поддерживает множественное наследование, каждый класс должен будет реализовать необходимый код для поддержки шаблона Singleton. Трейты предлагают решение именно такого рода проблем.
<?php
trait Singleton
{
private static $instance;
public static function getInstance() {
if (!(self::$instance instanceof Singleton)) {
self::$instance = new self;
}
return self::$instance;
}
}
class DbReader extends ArrayObject
{
use Singleton;
}
class FileReader
{
use Singleton;
}
?>
Трейт Singleton содержит реализацию шаблона Singleton со статическим методом getInstance(), который создает объект класса с использованием этого трейта (если он еще не создан) и возвращает его.
Попробуем создать объекты этих классов с помощью метода getInstance().
<?php
$a = DbReader::getInstance();
$b = FileReader::getInstance();
var_dump($a); //object(DbReader)
var_dump($b); //object(FileReader)
?>
Мы можем видеть, что $a является объектом DbReader, а $b является объектом FileReader, но оба теперь ведут себя как объекты реализующие шаблон Singleton. Метод от класса Singleton был введен в классы, использующие его трейт.
Трейты не налагают никакой дополнительной семантики на класс. В некотором роде вы можете думать об этом как о механизме копирования и вставки на уровне интерпретатора PHP, где методы этого признака копируются в класс компоновки.
Если мы просто расширим класс DbReader из родителя со скрытым свойством $instance, свойство не будет отображаться в дампе ReflectionClass::export().
Использование нескольких трейтов
До сих пор мы использовали только один трейт, но в некоторых случаях нам может потребоваться включить в класс функциональность более чем одного трейта.
<?php
trait Hello
{
function sayHello() {
echo "Hello";
}
}
trait World
{
function sayWorld() {
echo "World";
}
}
class MyWorld
{
use Hello, World;
}
$world = new MyWorld();
echo $world->sayHello() . " " . $world->sayWorld(); //Hello World
?>
Здесь у нас есть два трейта: "Привет" и "Мир". Трейт Hello может только сказать "Привет", а трейт World может сказать "Мир". В классе MyWorld мы применили Hello и World, чтобы объект MyWorld получал методы от обоих черт и мог сказать "Hello World".
В одной из следующих статей мы продолжим обсуждать трейты. А сегодня на этом все. Спасибо за внимание!
-
- Михаил Русаков
Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.