Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная №5. Объекты и классы в PHP.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
2 Мб
Скачать
☆

Деструктор

До сих пор мы только создавали новые величины (строки, массивы, числа) и объекты в программе на РНР, не задумываясь о том, что с ними происходит, когда они нам больше не нужны. В то же время, вопрос разрушения объектов и удаления их из памяти в ООП играет очень важную роль. Рассмотрим его чуть подробнее.

Вопрос освобождения ресурсов

Программы обычно пишут так, что за время их выполнения происходит создание и уничтожение большого числа самых разнообразных переменных. Действительно, когда РНР выходит из некоторой функции, он освобождает память, используемую всеми локальными переменными внутри этой функции. Если переменные имеют простую структуру (числа, строки или даже массивы), то обычное уничтожение - это как раз то, что нам нужно. Однако при использовании объектов ситуация усложняется - возникает проблема корректного освобождения ресурсов. Это объясняется тем, что объект при работе может использовать не только собственные свойства, но также и другие объекты, а также, что самое важное, различные внешние ресурсы (файлы, потоки, соединения с СУБД и т. д.).

Пусть, например, некоторый объект открывает в своем конструкторе файл. Вызов методов этого объекта позволяет каким-либо образом манипулировать с содержимым данного файла, например, считывать или записывать строки. Но ведь в конце работы файл необходимо закрыть, иначе при интенсивном создании и уничтожении объектов­файлов рано или поздно лимит на число открытых файловых дескрипторов окажется превышенным.

В листинге 9 приведен пример такого класса. Он оказывается довольно удобным на практике для ведения разных журналов. Главное достоинство классов - умение добавлять в каждую выводимую строчку сведения о текущей дате, причем независимо от того, имеются ли в переменной символы переноса строки или нет.

Листинr 9 Явное освобождение ресурсов. Файл File/LoggerO.php

Как видите, для ускорения работы данные не выводятся в файл сразу же после поступления: вначале они накапливаются в буфере $lines и записываются в журнал только во время выполнения close (). У нас получается своеобразная буферизация вывода (наподобие той, что встроена в РНР, но только на уровне каждого журнала).

Рассмотрим теперь скрипт, который использует данный класс (листинг 10). Предположим, мы ошиблись и не вызвали метод close () перед входом в очередную итерацию цикла (в примере правильный вызов close () отключен).

Листинг 10 Явное освобождение ресурсов. Файл destr0.php

В результате наш журнал test.log окажется пустым. Нам нужен какой-то механизм, который позволял бы гарантированно вызывать некоторый метод объекта, когда этот объект перестает использоваться в программе (и удаляется из памяти).

Описание деструктора

По аналогии с конструкторами обычно рассматриваются деструкторы. Деструктор - специальный метод объекта, который вызывается при уничтожении этого объекта (например, после завершения программы). Деструкторы обычно выполняют служебную работу - закрывают файлы, записывают протоколы работы, разрывают соединения, "форматируют жесткий диск" - в общем, освобождают ресурсы.

Деструктор - это специальный метод класса с именем _ destruct () , который будет гарантированно вызван при потере последней ссылки на объект в программе. Так как деструктор запускается самим РНР, он не должен принимать никаких параметров.

В листинге 11 приведен модифицированный класс с именем FileLogger, в котором объявляется деструктор. Теперь нам уже нет необходимости заботиться о "ручном" вызове close () в программе - РНР выполняет "финализирующие" действия самостоятельно.

Листинг 11 Деструктор. Файл File/Logger.php

Листинг 12 Использование класса с деструктором. Файл destr.php

Посмотрите на листинг 12. В нем мы последовательно создаем 10 объектов класса FileLogger, полагаясь на то, что их деструкторы будут вызваны в нужное время. Зададимся важным вопросом: в какой именно момент это произойдет? Интуитивно понятно, что деструктор вызывается в тот момент, когда объект в программе больше не нужен, и память, отведенную под него, можно освободить. Это событие в нашем случае происходит при перезаписи переменной $logger, т. е. когда ей присваивается новое значение (первая команда цикла).

Но задумайтесь, как РНР определяет, когда объект больше не нужен и его можно удалять из памяти? В нашем случае все просто: в единицу времени на объект ссылается лишь одна переменная $logger, но представьте, что бы произошло, если бы это оказалось не так. Например, мы можем накапливать объекты FileLogger в каком-нибудь массиве, и тогда уже на каждом обороте цикла вызова деструктора не произойдет:

Если вы модифицируете программу таким образом, то обнаружите, что она попрежнему работает! Записи в lоg-файл test.log добавляются, причем их очередность остается той же, что была ранее. Но в какой же момент РНР вызывает деструкторы десяти объектов в этом случае?