Объектно-ориентированное программирование на PHP. Сортировка объектов средствами SPL.

Владимир | | PHP, Web разработка.

К сожалению, использование объектно-ориентированных возможностей 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.