Объектно-ориентированный PHP: автоматическая загрузка классов, сериализация и получение информации об объектах
Добро пожаловать в четвертый урок из серии, посвященной ООП в PHP! Если вы пропустили первые три урока, вам возможно, захочется рассмотреть и их, дабы узнать подробнее о классах и объектах в PHP:
Если вы прошли все три предыдущих урока, то вы уже знакомы с основными концепциями ООП в PHP: классами, объектами, методами, полями и наследованием. В этом, последнем, уроке я постараюсь завершить тему объектно-ориентированного программирования в PHP, а также познакомить вас с некоторыми чрезвычайно полезными свойствами PHP, связанных с ООП:
- Как автоматически загружать классы;
- Как конвертировать объекты в строку и строку в объекты для удобства хранения и передачи;
- Как получить подробную информацию об определенном классе или объекте.
Готовы? Вперед!
Автоматическая загрузка классов
Как правило, полезно хранить каждый PHP класс в отдельном файле. Например, в приложении веб-форума, вы бы хранили класс Member в файле Member.php, а класс Topic - в файле Topic.php. Скорее всего, вы будете хранить все эти файлы в папке classes где-то на сайте:
classes/ Member.php Topic.php
Затем, если понадобится создать объект класса, например, Member, PHP сначала придется подключить файл с этим классом:
<?php require_once( "classes/Member.php" ); $member = new Member(); ?>
Хранение классов таким образом - вещь полезная не только для вашей психики, но и для использования такого удобного свойства, как автоматическая загрузка (autoloading).
Автоматическая загрузка работает так. Где-то в начале приложения PHP вы создаете специальную функцию __autoload(). В последствии, если где-то в коде будет попытка создать объект класса, о котором ничего не известно, PHP автоматически вызовет данную функцию, передав ей в качестве параметра имя искомого класса. Вся работа функции заключается в том, чтобы найти нужный файл и подгрузить его к скрипту, тем самым загрузить сам класс. После этого PHP уже сможет создать объект данного класса.
Давайте приведем пример. Напишем функцию __autoload() для автоматической загрузки классов из папки classes:
<?php function __autoload( $className ) { $className = str_replace( "..", "", $className ); require_once( "classes/$className.php" ); echo "Loaded classes/$className.php<br>"; } $member = new Member(); echo "Created object: "; print_r( $member ); ?>
Вот, как это работает. Сперва, создаем функцию __autoload() с входным параметром $className. В начале, функция убирает все подстроки “..” из полученного параметра, это делается в целях безопасности. Затем, с помощью функции require_once(), она подгружает нужный файл. Функции известно, что он находится в папке classes, и его расширение - .php. Функция также выводит на страницу сообщение, так что мы сразу увидим, что она отработала.
Затем протестим нашу функцию, создав объект класса Member. Так как мы предварительно не подгрузили файл с данным классом, PHP запустит функцию __autoload(), передав ей имя класса - “Member”. Она, в свою очередь, будет искать файл classes/Member.php. Затем PHP создает-таки объект Member. В завершении, отображаем сообщение о том, что объект создан.
Чтобы протестировать работу данного скрипта, создадим папку classes в том же каталоге, что и скрипт. Создадим в ней файл Member.php с простеньким классом:
<?php class Member { } ?>
Теперь, когда мы запустим скрипт, загрузится файл classes/Member.php, создастся объект класса Member, и на экране отобразится следующее:
Loaded classes/Member.php Created object: Member Object ( )
Автоматическая загрузка поможет вам сэкономить уйму времени, тем более, если у вас огромное количество классов. Вместо того, чтобы вызывать функцию require_once() в начале каждого файла, вы просто создаете в начале всего приложения функцию __autoload(), и отдаете управление загрузкой классов в руки PHP!
Сериализация объектов
Следующее свойство ООП, о котором я расскажу, - это конвертация объекта в строку и, наоборот, строки в объект. Это может быть полезно в случаях, когда вам нужно передавать объекты между скриптами и даже приложениями. Вот конкретные случаи:
- Передача объектов через поля веб-форм;
- Передача объектов через адресную строку;
- Хранение объекта в текстовом файле или одном поле таблицы базы данных.
Для конвертации объекта в строку, и обратно, используются следующие функции:
- serialize() - принимает объект и возвращает строковое представление его класса и свойств;
- unserialize() - принимает строку, созданную при помощи serialize(), и возвращает объект.
Давайте посмотрим на эти две функции в деле:
<?php class Member { public $username = ""; private $loggedIn = false; public function login() { $this->loggedIn = true; } public function logout() { $this->loggedIn = false; } public function isLoggedIn() { return $this->loggedIn; } } $member = new Member(); $member->username = "Fred"; $member->login(); $memberString = serialize( $member ); echo "Converted the Member object to a string: '$memberString'<br>"; echo "Converting the string back to an object...<br>"; $member2 = unserialize( $memberString ); echo $member2->username . " is " . ( $member2->isLoggedIn() ? "logged in" : "logged out" ) . "<br>"; ?>
Мы создали простенький класс Member с полем public $username, полем private $loggedIn и тремя методами public: login(), logout() и isLoggedIn(). Затем наш скрипт создает объект класса Member, дает ему имя "Fred" и логинит его.
Затем вызываем функцию serialize(), передав ей объект класса Member. serialize() возвращает строковое представление данного объекта, которое мы сохраним в переменной $memberString и отобразим на странице:
Converted the Member object to a string: 'O:6:"Member":2:{s:8:"username";s:4:"Fred";s:16:"MemberloggedIn";b:1;}'
Затем конвертируем нашу строку обратно в объект класса Member, вызвав функцию unserialize(), и сохраняем полученный объект в переменной $member2. Чтобы проверить, что наш объект сконвертировался верно и полностью, мы отображаем значение его поля $username и вызываем его метод isLoggedIn(), чтобы проверить, залогинился ли пользователь. Вот, что отобразится на странице:
Converting the string back to an object... Fred is logged in
Как видите, строка, созданная функцией serialize(), содержит имя класса, а также названия всех его полей и их значения для конкретного объекта. (Перед полями private записывается имя класса, без пробелов.) Тем не менее, названия методов класса не записываются в строку.
Чтобы сработала функция unserialize(), класс объекта, который должен быть сконвертирован из строки, должен подгружаться еще до того, как идет вызов unserialize(). Вы можете написать сам класс в том же скрипте, где вызывается unserialize(), или подгрузить файл с данным классом через функцию require_once(). Также вы можете создать функцию __autoload(), о которой мы говорили ранее. PHP вызовет __autoload(), если не сможет найти класс, объект которого вы пытаетесь сконвертировать.
На заметку: функции serialize() и unserialize() работают также и с другими типами данных, таких как массивы. Тем не менее, они не работают с ресурсами.
Функции __sleep() и __wakeup()
Иногда, перед сериализацией объекта, возникает необходимость кое-что почистить. Например, может понадобиться записать объект в базу данных и закрыть соединение. Подобно этому, после десериализации, вы захотите восстановить соединение и произвести еще какие-то действия.
В PHP есть несколько специальных методов, которые помогут вам в этом:
- __sleep() вызывается строго перед тем, как объект сериализуется с помощью функции serialize().
- __wakeup() вызывается сразу после того, как объект десериализуется с помощью unserialize().
Ваша функция __sleep() должна будет возвращать список полей класса. Именно тех полей, которые функция serialize() включит в возвращаемую строку. Вы можете использовать это для того, чтобы исключить ненужные поля из строкового представления объекта.
Давайте добавим в наш предыдущий пример методы __sleep() и __wakeup():
<?php class Member { public $username = ""; private $loggedIn = false; public function login() { $this->loggedIn = true; } public function logout() { $this->loggedIn = false; } public function isLoggedIn() { return $this->loggedIn; } public function __sleep() { echo "Cleaning up the object...<br>"; return array( "username" ); } public function __wakeup() { echo "Setting up the object...<br>"; } } $member = new Member(); $member->username = "Fred"; $member->login(); $memberString = serialize( $member ); echo "Converted the Member object to a string: '$memberString'<br>"; echo "Converting the string back to an object...<br>"; $member2 = unserialize( $memberString ); echo $member2->username . " is " . ( $member2->isLoggedIn() ? "logged in" : "logged out" ) . "<br>"; ?>
Вот, что отобразится на странице:
Cleaning up the object... Converted the Member object to a string: 'O:6:"Member":1:{s:8:"username";s:4:"Fred";}' Converting the string back to an object... Setting up the object... Fred is logged out
Обратите внимание на то, что:
- Наши методы __sleep() и __wakeup() в действительности ничего не подчищают и не задают; вместо этого, они просто выводят сообщения "Cleaning up the object..." и "Setting up the object...".
- Так как мы включаем только поле $username в массив, который возвращает __sleep(), в результирующей строке не будет присутствовать поле $loggedIn.
- В результате, поле $loggedIn десериализованного объекта примет значение по умолчанию - false, поэтому при вызове метода isLoggedIn() от десериализованного объекта, он вернет false. Вот, почему скрипт отобразит сообщение "Fred is logged out".
Если вы хотите написать метод __sleep() и чтобы все поля были сериализованы, тогда вам понадобится перечислять все поля для массива, который возвращает метод __sleep(). Этого легко достичь при помощи функций PHP array_keys() и get_object_vars() таким образом:
public function __sleep() { // почистить return array_keys( get_object_vars( $this ) ); }
На заметку: другой классный способ сериализации объектов (причем, кросс-платформенный) - это конвертирование строк JSON.
Получение информации о классах и объектах
В PHP есть много полезных функций для получения информации о классах и объектах. Это полезно в случаях, когда нужно работать с объектами из другого приложения, а также поможет вам написать удобный, гибкий код. Используя эти функции для объекта, вы можете получить имя его класса, проверить, создан ли он от определенного класса, получить его поля и методы и др.
Вот краткий перечень наиболее часто употребляемых из них:
Функция | Описание |
get_class( $obj ) | Возвращает имя класса, которому принадлежит объект $obj |
get_parent_class($className или $obj ) | Возвращает имя класса, который является родителем класса $className, или родителем класса, чьим объектом является $obj |
is_a( $obj, $className ) | Возвращает true, если $obj - объект класса $className, или если $obj - объект класса - потомка $className |
$obj instanceof $className | Делает то же самое, что и функция is_a() |
get_class_methods($className или $obj ) | Возвращает массив названий всех методов класса $className или объекта $obj |
get_class_vars( $className ) | Возвращает ассоциативный массив всех полей класса $className вместе с их значениями по умолчанию |
get_object_vars( $obj ) | Возвращает ассоциативный массив всех полей объекта $obj, вместе с их текущими значениями |
Важно отметить, что такие функции, как get_class_methods(), get_class_vars() и get_object_vars(), возвращают только те методы и поля, которые находятся в одной области действия с кодом, их вызывающим. Например, метод private будет включен в возвращаемое значение функции get_class_methods(), только если get_class_methods() вызывается внутри метода класса.
Давайте поэкспериментируем с некоторыми из этих функций на таком примере:
<?php class Member { public $username = ""; private $loggedIn = false; public function login() { $this->loggedIn = true; } public function logout() { $this->loggedIn = false; } public function isLoggedIn() { return $this->loggedIn; } public function listMyProperties() { echo "My properties are: "; print_r( get_object_vars( $this ) ); } } class Administrator extends Member { public $adminLevel = 1; public function createForum( $forumName ) { echo "$this->username created a new forum: $forumName<br>"; } public function banMember( $member ) { echo "$this->username banned the member: $member->username<br>"; } } $admin = new Administrator(); $admin->username = "Mary"; $admin->login(); echo "1. $admin->username's class is " . get_class( $admin ) . "<br>"; echo "2. $admin->username's parent class is " . get_parent_class( $admin ) . "<br>"; echo "3. Is $admin->username a Member? " . ( is_a( $admin, "Member" ) ? "Yes" : "No" ) . "<br>"; echo "4. $admin->username's methods are: "; print_r( get_class_methods( $admin ) ); echo "<br>5. $admin->username's class properties are: "; print_r( get_class_vars( get_class( $admin ) ) ); echo "<br>6. $admin->username's object properties are: "; print_r( get_object_vars( $admin ) ); echo "<br>7. "; $admin->listMyProperties(); ?>
В скрипте создается класс Member с несколькими полями и методами. Также в нем создается класс Administrator - дочерний от класса Member. В классе Administrator добавляется поле public $adminLevel, а также пара методов: createForum() и banMember(), которые будут только у объектов класса Administrator.
После создания класса, мы создаем объект класса Administrator, сохраняем его в переменной $admin, даем ему имя "Mary" и логиним админа при помощи вызова метода login().
В последней части скрипта (строки 44-54), мы применяем различные функции к нашим объектам и классам. Вот результат работы данного кода:
Mary's class is Administrator Mary's parent class is Member Is Mary a Member? Yes Mary's methods are: Array ( [0] => createForum [1] => banMember [2] => login [3] => logout [4] => isLoggedIn [5] => listMyProperties ) Mary's class properties are: Array ( [adminLevel] => 1 [username] => ) Mary's object properties are: Array ( [adminLevel] => 1 [username] => Mary ) My properties are: Array ( [adminLevel] => 1 [username] => Mary [loggedIn] => 1 )
Вот, как отработают данные функции:
- get_class( $admin ) возвращает строковое значение "Administrator".
- get_parent_class( $admin ) возвращает строковое значение "Member".
- is_a( $admin, "Member" ) возвращает true.
- get_class_methods( $admin ) возвращает массив названий методов для классов Administrator и Member. Так как все эти методы - public, они все будут записаны в массив.
- get_class_vars( $admin ) возвращает массив названий полей public и соответствующих им значений по умолчанию для классов Administrator и Member.
- get_object_vars( $admin ) возвращает массив названий полей public и соответствующих им текущих значений.
- В конце вызываем метод класса Member - listMyProperties(). Этот метод вызывает функцию get_object_vars() и отображает результат. Тем не менее, так как get_object_vars() теперь вызывается изнутри класса, он также возвращает поле private - $loggedIn.
Как видите, в PHP очень легко извлечь любую информацию об объекте или классе. В PHP есть еще функции для получения инфы об объекте, классе и интерфейсе, например, class_exists(), get_called_class(), get_declared_classes(), get_declared_interfaces(), interface_exists(), is_subclass_of(), method_exists() и property_exists().
Итоги
В этом уроке вы ознакомились с тремя полезнейшими свойствами PHP объектов:
- Использование функции __autoload() для автоматической загрузки файлов с необходимыми классами;
- Как конвертировать объекты в строки и обратно при помощи функций PHP serialize() и unserialize();
- Получение информации об объектах, классах, предках при помощи PHP функций.
С помощью этих трех свойств работать с классами и объектами в PHP не составит огромного труда.
Надеюсь, вам понравилась данная серия уроков, посвященная ООП в PHP! Если вы прошли все 4 урока, у вас достаточно знаний для написания классных PHP сайтов и приложений. Однако, на этом история не заканчивается — в PHP еще много полезных свойств, предназначенных для работы с ООП, например:
- Итерация: как последовательно пройтись по всем полям объекта;
- Больше специальных методов, включая __callStatic(), __isset(), __unset(), __toString(), __invoke(), __set_state() и __clone()
- Паттерны: техника, позволяющая достичь много целей при помощи объектов;
- Копирование и сравнение объектов;
- Статическое позднее связывание, которое дает кучу возможностей при вызове статических наследуемых методов.
Если у меня будет время, и если у вас будет такая необходимость, я обязательно расскажу о них в следующих уроках.
Удачного кодирования!
Источник: http://feedproxy.google.com/~r/ruseller/CdHX/~3/mY6IWaHuUNo/lessons.php
Дайджест новых статей по интернет-маркетингу на ваш email
Новые статьи и публикации
- 2024-09-30 » Как быстро запустить Laravel на Windows
- 2024-09-25 » Next.js
- 2024-09-05 » OpenAI рассказал, как запретить ChatGPT использовать содержимое сайта для обучения
- 2024-08-28 » Чек-лист: как увеличить конверсию интернет-магазина на примере спортпита
- 2024-08-01 » WebSocket
- 2024-07-26 » Интеграция с Яндекс Еда
- 2024-07-26 » Интеграция с Эквайринг
- 2024-07-26 » Интеграция с СДЕК
- 2024-07-26 » Интеграция с Битрикс-24
- 2024-07-26 » Интеграция с Travelline
- 2024-07-26 » Интеграция с Iiko
- 2024-07-26 » Интеграция с Delivery Club
- 2024-07-26 » Интеграция с CRM
- 2024-07-26 » Интеграция с 1C-Бухгалтерия
- 2024-07-24 » Что такое сторителлинг: техники и примеры
- 2024-07-17 » Ошибка 404: что это такое и как ее использовать для бизнеса
- 2024-07-03 » Размещайте прайс-листы на FarPost.ru и продавайте товары быстро и выгодно
- 2024-07-01 » Профилирование кода в PHP
- 2024-06-28 » Изучаем ABC/XYZ-анализ: что это такое и какие решения с помощью него принимают
- 2024-06-17 » Зачем вам знать потребности клиента
- 2024-06-11 » Что нового в работе Яндекс Метрики: полный обзор обновления
- 2024-06-11 » Поведенческие факторы ранжирования в Яндексе
- 2024-06-11 » Скорость загрузки сайта: почему это важно и как влияет на ранжирование
- 2024-05-27 » Подборка сервисов для расшифровки аудио в текст
- 2024-05-27 » PostgreSQL 16. Изоляция транзакций. Часть 2
- 2024-05-06 » Как настраивать конверсионные стратегии: работа над ошибками
- 2024-04-22 » Комментирование кода и генерация документации в PHP
- 2024-04-22 » SEO в России и на Западе: в чем основные отличия
- 2024-04-22 » SEO для международного масштабирования
- 2024-04-22 » Как использовать XML-карты для продвижения сайта
Одного яйца два раза не высидишь. К. Прутков |
Мы создаем сайты, которые работают! Профессионально обслуживаем и продвигаем их , а также по всей России и ближнему зарубежью с 2006 года!
Как мы работаем
Заявка
Позвоните или оставьте заявку на сайте.
Консультация
Обсуждаем что именно Вам нужно и помогаем определить как это лучше сделать!
Договор
Заключаем договор на оказание услуг, в котором прописаны условия и обязанности обеих сторон.
Выполнение работ
Непосредственно оказание требующихся услуг и работ по вашему заданию.
Поддержка
Сдача выполненых работ, последующие корректировки и поддержка при необходимости.