Если вы когда-либо изучали PHP-код проектов с открытым исходным кодом, вы, возможно, сталкивались с методами, начинающимися с двойного подчеркивания.
Это те самые волшебные методы, с помощью которых вы сможете определить поведение вашего объекта при различных манипуляциях с его экземпляром.
Я предполагаю, что вы уже сталкивались с некоторыми из них, поскольку существуют довольно распространенные методы, но я по-прежнему считаю, что компетентный программист PHP должен хорошо разбираться во всех особенностях языка.
Я думаю, это можно считать своего рода отправной точкой в мир магических методов.
Приступаем к учебе
Когда я сам изучал этот материал, я пользовался всевозможными учебниками и статьями, в которых приводились довольно глупые или вообще бесполезные примеры.Я считаю, что для того, чтобы что-то понять, нужно попробовать это в контексте реальной проблемы.
Вот с этого мы и начнем.
Давайте представим, что мы хотим получать все твиты с помощью API Tweeter. Мы получаем JSON всех твитов текущего пользователя и хотим превратить каждый твит в объект с методами, которые позволят нам выполнять определенные операции.
Ниже я представил базовый класс Tweet:
Теперь, когда мы создали объект, мы можем приступить к изучению самих методов.class Tweet { }
(Примечание переводчика – некоторые конструкции иногда будут опущены, чтобы подчеркнуть роль и возможности каждого метода)
Конструкторы и деструкторы
Пожалуй, одним из наиболее распространенных магических методов является конструктор ( __construct() ).Если вы достаточно внимательно следили за созданием приложения Cribbb в моем блоге, вы вполне знакомы с этим методом.
Метод __construct() вызывается автоматически при создании экземпляра объекта.
В нем вы можете задать исходные свойства объекта или установить зависимости.
Пример использования: public function __construct($id, $text)
{
$this->id = $id;
$this->text = $text;
}
$tweet = new Tweet(123, 'Hello world');
Когда мы создаем экземпляр класса Tweet, мы можем передать параметры, которые будут переданы в метод __construct().
Из примера выше видно, что мы не вызываем этот метод и не должны его вызывать — он вызывается автоматически.
Со временем вам понадобится расширить класс, унаследовав его.
Иногда родительский класс также имеет метод __construct(), выполняющий определенные действия, поэтому, чтобы не потерять функциональность родительского класса, нужно вызвать его конструктор.
class Entity {
protected $meta;
public function __construct(array $meta)
{
$this->meta = $meta;
}
}
class Tweet extends Entity {
protected $id;
protected $text;
public function __construct($id, $text, array $meta)
{
$this->id = $id;
$this->text = $text;
parent::__construct($meta);
}
}
При попытке удалить объект будет вызван метод __destruct().
Опять же, по аналогии с конструктором, это не то, что нужно вызывать, потому что PHP все сделает за вас.
Этот метод позволит вам очистить все, что вы использовали в объекте, например соединение с базой данных.
public function __destruct()
{
$this->connection->destroy();
}
Честно говоря, я скрыл от вас большую часть описанного выше метода __destruct().
PHP на самом деле не тот язык, в котором процесс будет существовать достаточно долго, поэтому я не думаю, что у вас будет что-то, для чего понадобится деструктор.
Жизненный цикл запроса в самом PHP настолько короток, что этот метод принесет больше хлопот, чем пользы.
Геттеры и сеттеры
Когда вы работаете с объектами в PHP, вам бы хотелось получить доступ к свойствам объекта примерно так: $tweet = new Tweet(123, 'hello world');
echo $tweet->text; // 'hello world'
Однако если для свойства text установлен модификатор доступа protected, то такой вызов вызовет ошибку.
Волшебный метод __get() перехватывает вызовы любых закрытых свойств.
public function __get($property)
{
if (property_exists($this, $property)) {
return $this->$property;
}
}
Метод __get() принимает в качестве аргумента имя свойства, к которому вы обращаетесь.
В приведенном выше примере сначала проверяется наличие свойства у объекта и, если оно существует, возвращается его значение.
Как и в примерах выше, не следует вызывать этот метод напрямую; PHP будет вызывать его каждый раз, когда вы пытаетесь получить доступ к закрытым свойствам класса.
В противоположной ситуации — если вы попытаетесь установить значение свойства, которое не является общедоступным, — вы получите ошибку.
И опять же, в PHP есть собственный метод, который будет вызываться, когда вы попытаетесь установить значение в закрытом поле.
Этот метод принимает в качестве аргументов 2 параметра — свойство, в которое хотели записать значение, и само значение.
Если вы хотите использовать этот метод, ваш класс получит такое свойство: public function __set($property, $value)
{
if (property_exists($this, $property)) {
$this->$property = $value;
}
}
$tweet->text = 'Setting up my twttr';
echo $tweet->text; // 'Setting up my twttr'
В примерах выше я показал, как можно получить или установить значения свойств, не имеющих модификатора публичного доступа.
Однако работать с этими волшебными методами не всегда будет лучшей идеей.
Гораздо лучше иметь несколько методов для получения и записи свойств, потому что тогда они образуют определенный API, а это означает, что ваш код не сломается, если вы измените способ его хранения или обработки.
Однако иногда вы все равно будете сталкиваться с методами __get() и __set(), которые обычно называются геттерами и сеттерами соответственно.
Это довольно хорошее решение, если вы решите изменить какое-то значение или добавить бизнес-логику.
Проверка объекта на наличие
Если вы знакомы с PHP, вы, вероятно, знаете о функции isset(), которая обычно используется при работе с массивами.Вы также можете использовать эту функцию, чтобы понять, установлено ли свойство в объекте или нет. Вы сможете определить магический метод __isset(), чтобы проверять не только публичные свойства, но и другие.
public function __isset($property)
{
return isset($this->$property);
}
isset($tweet->text); // true
Как вы можете видеть выше, метод __isset() отслеживает вызов функции на предмет ее существования и получает имя свойства в качестве аргумента.
В свою очередь, в методе вы можете использовать функцию isset() для проверки существования.
Очистка переменной Подобно функции isset(), функция unset() обычно используется при работе с массивами.
Опять же, вы можете использовать функцию unset(), чтобы очистить значение закрытого свойства.
Чтобы применить этот метод к закрытым свойствам, вам понадобится метод __unset(), который будет отслеживать попытки очистки закрытых свойств класса.
public function __unset($property)
{
unset($this->$property);
}
Приведение к строке
Метод __toString() позволит вам определить логику вашего приложения при попытке привести объект к строковому типу.
Например: public function __toString()
{
return $this->text;
}
$tweet = new Tweet(1, 'hello world');
echo $tweet; // 'hello world'
Вы можете сказать, что когда вы пытаетесь получить доступ к объекту как к строке, например, при использовании echo, объект будет возвращен так, как вы определили в методе __toString().
Хорошей иллюстрацией в данном случае являются Eloquent Models из фреймворка Laravel. Когда вы попытаетесь привести объект к строке, вы получите json. Если вы хотите увидеть, как Laravel это делает, я рекомендую посмотреть исходный код .
Сон и пробуждение
Функция сериализации (serialize()) — довольно распространенный способ хранения объекта.Например, если вы хотите сохранить объект в базе данных, вам сначала придется сериализовать его, затем сохранить, а когда он вам снова понадобится, вам придется получить его и десериализовать ( unserialise() ).
Метод __sleep() позволяет вам определить, какие свойства следует сохранить.
Если бы мы, например, не хотели поддерживать какие-либо соединения или внешние ресурсы.
Давайте представим, что когда мы создаем объект, мы хотим определить механизм его сохранения.
$tweet = new Tweet(123, 'Hello world', new PDO ('mysql:host=localhost;dbname=twttr', 'root'));
Когда мы готовим объект к сохранению, нам естественно не нужно сохранять подключение к базе данных, потому что в дальнейшем это будет бессмысленно.
Поэтому в методе __sleep() мы определим массив свойств, которые необходимо сохранить.
public function __sleep()
{
return array('id', 'text');
}
А после того, как придет время пробуждения объекта, нам может понадобиться все, что мы не сохранили при сериализации.
В этом конкретном примере нам нужно установить соединение с базой данных.
Это можно сделать с помощью магического метода __wakeup().
public function __wakeup()
{
$this->storage->connect();
}
Методы вызова
Волшебный метод __call() перехватит все попытки вызвать методы, которые не являются публичными.
Например, у вас может быть массив данных, который вы хотите изменить: class Tweet {
protected $id;
protected $text;
protected $meta;
public function __construct($id, $text, array $meta)
{
$this->id = $id;
$this->text = $text;
$this->meta = $meta;
}
protected function retweet()
{
$this->meta['retweets']++;
}
protected function favourite()
{
$this->meta['favourites']++;
}
public function __get($property)
{
var_dump($this->$property);
}
public function __call($method, $parameters)
{
if (in_array($method, array('retweet', 'favourite')))
{
return call_user_func_array(array($this, $method), $parameters);
}
}
}
$tweet = new Tweet(123, 'hello world', array('retweets' => 23, 'favourites' => 17));
$tweet->retweet();
$tweet->meta; // array(2) { ["retweets"]=> int(24) ["favourites"]=> int(17) }
Другой типичный пример — использование другого общедоступного API в вашем объекте.
class Location {
Теги: #обучение #php #магические методы #php
-
Получение Правильного Текстового Файла
19 Oct, 24 -
Мир Онлайн-Шоппинга
19 Oct, 24 -
Холодович Александр Алексеевич
19 Oct, 24 -
Алгоритмы На Чипе (Анонс Книги)
19 Oct, 24 -
Новая Демо-Версия Игры Hammerfight
19 Oct, 24