PHP5. Ссылки на объекты. Внешние и внутренние

В PHP5 все переменные - это ссылки на содержимое переменной. Для получения доступа к содержимому переменной используются ссылками. Важно помнить, что эти ссылки не есть указатели как в C/C++, которые содержат адреса на ячейки памяти, они лишь ссылаются на некоторое содержимое. Так же дело обстоит и с ссылками в python`е. Но сейчас не об этом. В PHP5 ссылка по-сути своей определяет жизнь переменной, точнее того, куда она ссылается: при удалении переменной ее содержимое может не сразу удалиться. С чем это может быть связано? За такую очистку как мы знаем отвечает сборщик мусора (garbage collector). А он смотрит как раз на то, есть ли ссылки на данные или нет, если нет, то все будет почищено, а иначе зачистка будет пропущена. Продемонстрирую на примере.

class Node
{
    var $str; // внутренние данные
    var $ref; // внетренняя ссылка
  
    // получение внутренних данных
    function getStr()
    {
        return $this->str;
    }
  
    // установить внутренние данные
    function setStr( $str )
    {
        $this->str = $str;
    }
  
    // получить внешнюю ссылку
    function getNext()
    {
        return $this->ref;
    }
  
    // установить внешнюю ссылку
    function setNext( &$ref )
    {
        $this->ref = $ref;
    }
  
    function __construct()
    {
        echo 'constructor<br/>';
    }
  
    function __destruct()
    {
        echo 'destructor -> '.$this -> getStr().'<br/>';
    }
  
}

// Создаем первый объект. Переменная получает ссылку на данный объект
$first = new Node;
// Создаем второй объект. Переменная получает ссылку на данный объект
$second = new Node;

// Помещаем данные в первый объект
$first->setStr( '$first' );
// Помещаем данные во второй объект
$second->setStr( '$second' );

// Привязываем первый объект ко второму за счет ссылки внутреннего члена $ref на второй объект
$first->setNext( $second );
// Привязываем второй объект к первому за счет ссылки внутреннего члена $ref на первый объект
$second->setNext( $first );

// Удаляем переменную $first, тем самым мы уничтожаем ее ссылку на объект
unset( $first );
// Удаляем переменную $second, тем самым мы уничтожаем ее ссылку на объект
unset( $second );

echo 'Debug<br/>';


Если мы запустим данный код на исполнение, то получим следующий результат:

constructor
constructor
Debug
destructor -> $first
destructor -> $second


Вроде бы ничего особенного, но присмотритесь на месторасположение слова Debug. Ведь мы уничтожили все переменные до момента вывода этого слова командами unset( $first ) и unset( $second ). То есть должны были сработать деструкторы наших объектов. Но на деле видим, что это не так. В чем дело? На самом деле мы создали перекрестные ссылки между первым и вторым объектами. Эти ссылки внутренние, и поэтому когда мы уничтожили наши переменные, мы уничтожили лишь внешние ссылки на объекты. В то время как объекты продолжали свое существование. Ну а на момент завершения сценария, как мы знаем, освобождаются все ресурсы, вот и получаем в конце вызовы деструкторов.
Теперь попробуйте закомментировать строчки, где идет создание внутренних перекрестных ссылок:

// $first->setNext( $second);
// $second->setNext( $first );


В результате получаем следующий результат:

constructor
constructor
destructor -> $first
destructor -> $second
Debug


Отсюда видим, что теперь наши объекты спокойно уничтожаются, что подтверждается сообщениями от их деструкторов до слова Debug. Все верно, ведь теперь на них ничто и никто не ссылается, вот и срабатывает сборщик мусора. Обратите внимание в описании класса Node на метод setNext() который работает непосредственно со ссылками. Всем удачи!