Объектно-ориентированное программирование (ООП), классы
Автор: Дмитрий Лебедев
Популярное объяснение понятий
"класс" и "объект" и с чем их едят.
Мой путь к пониманию объектов шел слишком долго. Надо
сказать, что закончился он чрезвычайно неожиданно - я
прочел... мануал PHP 4. Где можно найти толковое описание,
только не там, казалось бы... Правда, уже до этого я кое-что
знал ("...объект, сочетающий в себе как совокупность данных,
так и действий над ними." (с) Епанешников, "Программирование в
среде Turbo Pascal 7.0"), но это уже детали.
Что же такое класс и объект. Сперва об объекте. Определение
"...сочетающий в себе как совокупность данных, так и действий
над ними" - вполне подходящее. Если говорить "приземленно", то
объект в PHP - это переменная особого типа. В ней содержатся
специально объявленные под-переменные и функции этого объекта
(то, что объект содержит переменные и функции, в научной
литературе называется инкапсуляцией). Функция is_object на эту
переменную выдает true:
if (is_object($objectname)) {
do_something();
};
Обращение к под-переменной объекта производится следующим
образом (название, конечно же неправильное, правильно
"свойство объекта").
$objectname->property
print ($objectname->property);
//Вызов функции (метода) объекта:
$objectname->format_output($format);
Конечно же неудобно писать имя объекта и "стрелочку"
("->") перед нужной переменной, но это только поначалу.
Зато потом можно сэкономить большой объем программного кода (и
избежать лишней головной боли).
Теперь что такое класс. Класс - значит класс объектов. В
PHP-скриптах описывается не объект. Сначала описывается класс
объектов, и затем можно создавать сколько угодно объектов
этого класса.
<?
class Public_Transport {
var $capacity = 0;
var $passengers = 0;
var $stop = array();
var $current_stop = 0;
var $vehicle = "unknown";
function say_stop () {
echo $this->stop[$this->current_stop];
if ($this->current_stop==sizeof($this->stop)-1)
echo ". Конечная.";
else
echo " следующая - ", $this->stop[$this->current_stop+1];
}
function stop () {
$this->passengers += intval(rand((-1*$this->passengers),100));
if ($this->passengers > $this->capacity) {
echo "Освобождаем двери!";
$this->passengers = $this->capacity;
};
}
function go () {
$this->current_stop++;
}
}
?>
ВНИМАНИЕ! Закрывающая скобка
класса должна быть без точки с запятой (""), как и все
описания функций внутри описания класса.
Программа, работающая с классом Общественный_Транспорт
будет выглядеть так:
<?
$bus = new Public_Transport;
$bus->capacity = 200;
$bus->vehicle = "Лиаз-767";
$bus->stop = array ("Торговый центр", "Поликлиника", "Институт теплофизики",
"Вычислительный центр", "Институт ядерной физики", "Институт гидродинамики",
"Морской проспект", "Дом ученых", "ул. Жемчужная", "Цветной проезд");
while ($bus->current_stop < sizeof($bus->stop)) {
$bus->say_stop();
$bus->stop();
$bus->go();
};
?>
В этом примере запущен только один автобус, а можно и два,
и три, и сколько угодно. Понятно, что это можно повторить и
без помощи объектов, но это сложнее, и полученный код не так
легко читается, как с объектами, тем более, когда "предметов"
несколько.
Объект и его свойства являются обычными переменными.
Например, можно работать с динамическими именами переменных:
<?
$a = "bukva a";
$b = "bukva b";
$c = "a";
echo $$c;
?>
Такой код выведет "bukva a". И то же самое можно делать с
объектами и их свойствами:
<?
class someclass1 {
var $a = 1;
var $b = 2;
var $c = 3;
}
class someclass2 {
var $a = 4;
var $b = 5;
var $c = 6;
}
$d = new someclass1;
$e = new someclass2;
$f = "d";
$g = "c";
echo ${$f}->{$g};
?>
(такой код выдаст "3")
То же касается и динамических имен функций.
На нашем портале написано подробно о динамичесих
именах переменных и изменяемых
именах функций.
И на прощанье вот что. В начале года мне надо было написать
скрипт для рассылки новостей и прайс-листов подписчикам. Зашел
я на сайт PHP и заглянул в мануал по
функции mail(), чтобы найти что-нибудь про аттачмент. В
комментариях к функции я нашел то, что искал - класс для
вложения файла в письмо. За восемь месяцев туда накидали много
ссылок на такие классы, а в феврале он был единственный - CMailFile.
Так вот, как они делают - делать не надо (я тогда в классах
разбирался смутно, и просто вырезал функции, несколько
упростив код). Процитирую заголовки функций:
class CMailFile {
var $subject;
var $addr_to;
var $text_body;
var $text_encoded;
var $mime_headers;
var $mime_boundary = "--==================_846811060==_";
var $smtp_headers;
function CMailFile($subject,$to,$from,$msg,$filename,
$mimetype = "application/octet-stream", $mime_filename = false) {
/* если функция имеет то же имя, что и класс, то это будет конструктор класса */
function attach_file($filename,$mimetype,$mime_filename) {
/* Вот это не понимаю! attach_file вызывается из функции CMailFile - зачем?
Только для красоты. А так - можно было этот кусок кода вставить прямо в главную
функцию, раз уж решено сделать единовременный вызов функции. Далее идут несколько
функций того же назначения и характера. */
function encode_file($sourcefile) {
function sendfile() {
function write_mimeheaders($filename, $mime_filename) {
function write_smtpheaders($addr_from) {
}
/* А вот пример использования класса. */
// usage - mimetype example "image/gif"
// $mailfile = new CMailFile($subject,$sendto,$replyto,$message,$filename,$mimetype);
// $mailfile->sendfile();
Зачем было оформлять это как класс - непонятно. Только для
красоты и разделения функции на несколько штук. А вообще-то,
если я захочу на ходу поменять адресата (например, для той же
рассылки, когда я прохожу циклом по массиву адресов), надо
снова вызывать функцию CMailFile, которая перекодирует файл
снова, требуя определенных системных ресурсов.
Раз уж я начал ругать другого, покажу, как по моему мнению
правильнее использовать ООП для рассылки писем. В следующем
выпуске посвященном приемам ООП (а перед, думаю, ним будуд два
других) я хочу привести пример использования класса для
отправки почтовых сообщений, в том числе для
рассылок.