К сожалению, использование объектно-ориентированных возможностей PHP встречается не так часто, как хотелось бы. Конечно, тут есть объективные причины, например, не все хостеры предоставляют PHP5 (именно с этой версии появилась нормальная поддержка ООП).
К тому же, огромное количество PHP скриптов написано без использования ООП. И во многих случаях нет необходимости их переписывать.
Но ООП – это не «модная фишка». Эта парадигма программирования при правильном использовании позволяет сделать php скрипты понятнее, сократить количество ошибок, и, самое главное, увеличить скорость разработки (за счет повторного использования кода).
В этой заметке я хочу рассказать о нескольких таких возможностях и показать пример работы с SPL (StandardPHPLibrary).
Предположим, у нас есть задача, нужно отсортировать массив. Ничего сложного, можно просто использовать функцию sort
.
Но, представим, что задача немного сложнее. Сортировать нужно сложные объекты, например, экземпляры классов. Они обычно содержат несколько свойств (переменных), каждое из которых может быть использовано при сортировке.
В таком случае можно написать собственную функцию сравнения двух объетов (назовем ее cmpObjects
), а затем использовать функцию uasort
. Ей в первом параметре передается массив, а во втором – имя функции, которая сравнивает объекты.
В принципе, задача решена. Но функция cmpObjects
, с точки зрения PHP, никак не связана с объектами, которые она сравнивает. Хотя очевидно, что использовать ее с другими объектами будет бессмысленно. ООП позволяет устранить этот недосток.
Идея заключается в том, чтобы поместить функцию сравнения внутри класса, экземпляры которого она сравнивает.
Примечание. Если следовать терминологии ООП, то функции, объявленные внутри класса, нужно называть методами, а переменные — свойствами.
Рассмотрим конкретный пример.
<?php class MyClass { private $name; private $age; public function MyClass($name, $age) { $this->name = $name; $this->age = $age; } public function getName() { return $this->name; } public function getAge() { return $this->age; } public function toString() { return 'Имя: '.$this->name.'; Возраст: '.$this->age; } public static function ageCmp($val1, $val2) { if ($val1->getAge() === $val2->getAge()) { return 0; } return ($val1->getAge() >= $val2->getAge()) ? 1 : -1; } public static function nameCmp($val1, $val2) { return strcmp($val1->getName(), $val2->getName()); } } ?>
Как видите, этот класс имеет два свойства (name
и age
), два метода для чтения этих свойств (getName
, getAge
), конструктор, метод toString
(возвращает значения свойств в виде строки) и два метода сравнения.
Первый метод (ageCmp
) в качестве основы сравнения использует свойство age
, а второй (nameCmp
) — name
. Принцип их работы прост. Если первый объект (val1
) больше второго (val2
), возвращаем «1», если меньше – «-1», а если они равны – «0».
Обратите внимание на ключевое слово static
в объявлении этих методов. Оно позволяет их использовать, не создавая экземпляр класса. Т.е. не нужно выполнять new MyClass(...);
.
Теперь рассмотрим, как использовать этот класс. Напишем небольшой скрипт.
include "myclass.php"; $v1 = new MyClass('Ваня', 15); $v2 = new MyClass('Петя', 17); $v3 = new MyClass('Коля', 13); $data = array($v1, $v2, $v3); $dataIterator = new ArrayIterator($data); foreach ($dataIterator as $val) { echo $val->toString().'<br />'; } echo "Сортировка по возрасту<br />"; $dataIterator->uasort('MyClass::ageCmp'); $dataIterator->rewind(); foreach ($dataIterator as $val) { echo $val->toString().'<br />'; } echo "Сортировка по имени<br />"; $dataIterator->uasort('MyClass::nameCmp'); $dataIterator->rewind(); foreach ($dataIterator as $val) { echo $val->toString().'<br />'; }
Прежде всего, мы подключаем файл с объявлением класса, создаем три объекта ($v1
, $v2
, $v3
) и формируем из них массив.
Затем создаем объект типа ArrayIterator
и передаем его конструктору наш массив.
Примечание. ArrayIterator
входит в библиотеку SPL, а документация с его описанием находится здесь.
Теперь мы можем использовать $dataIterator
для работы с массивом.
Как видите, $dataIterator
можно использовать в циклах foreach
, т.е. работать как с обычным массивом.
Но в тоже время, его возможности гораздо шире.
Во-первых, обратите внимание на метод rewind()
. Он перемещает указатель на первый элемент массива.
Во-вторых, ArrayIterator
имеет свой метод uasort, который мы используем для сортировки. Первый раз (строка 16) мы выполняем сортировку с помощью метода ageCmp
, а после этого (строка 25) – используя nameCmp
.
В результат работы скрипта будет выглядеть так:
Имя: Ваня; Возраст: 15
Имя: Петя; Возраст: 17
Имя: Коля; Возраст: 13
Сортировка по возрасту
Имя: Коля; Возраст: 13
Имя: Ваня; Возраст: 15
Имя: Петя; Возраст: 17
Сортировка по имени
Имя: Ваня; Возраст: 15
Имя: Коля; Возраст: 13
Имя: Петя; Возраст: 17
Как видите, массив мы отсортировали 😉
Самое главное, что основной скрипт не содержит кода сортировки и практически ничего не знает о классе. Т.е. мы можем вместо MyClass использовать другой класс. И это потребует минимальных изменений кода.
До встречи!
Интересно почитать:
Новые стандарты хостинга — yeshost.ru.