Мой путь к пониманию объектов шел слишком долго. Надо сказать, что закончился он чрезвычайно неожиданно - я прочел... мануал 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(); }; ?>
В этом примере запущен только один автобус, а можно и два, и три, и сколько угодно. Понятно, что это можно повторить и без помощи объектов, но это сложнее, и полученный код не так легко читается, как с объектами, тем более, когда "предметов" несколько.
Объект и его свойства являются обычными переменными. Например, можно работать с динамическими именами переменных:
Такой код выведет "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")
То же касается и динамических имен функций.
В руководстве по PHP4 написано подробнее о динамичесих именах переменных и изменяемых именах функций.
И на прощанье вот что. В начале года мне надо было написать скрипт для рассылки новостей и прайс-листов подписчикам. Зашел я на сайт 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, которая перекодирует файл снова, требуя определенных системных ресурсов.
Раз уж я начал ругать другого, покажу, как по моему мнению правильнее использовать ООП для рассылки писем. В следующем выпуске посвященном приемам ООП (а перед, думаю, ним будуд два других) я хочу привести пример использования класса для отправки почтовых сообщений, в том числе для рассылок.