uznay-chto-hochesh.narod.ru

-сайт для интересующихся людей

Учебник - справочник по PHP.

Здесь Вы найдете что хотели

Меню сайта
Главная
Введение
Справочник языка
Возможности РНР
Функции (справочник)
Расширение РНР 4.0
F.A.Q. частые вопросы
Приложения
Алфавитный указатель
Друзья сайта
сделай сайт сам! пособие по html
изучение html и web-дизайна для новичков
Бесплатная отправка смс на все операторы
Реклама
 
Назад Глава 13. Классы и Объекты Вперёд

Ссылки внутри конструктора

Создание ссылок внутри конструктора может привести к неожиданным результатам. В этом разделе сделана попытка помочь избежать проблем.

class Foo
{
    function Foo($name)
    {
        // создать ссылку внутри глобального массива $globalref
        global $globalref;
        $globalref[] = &$this;
        // установить имя передаваемого значения
        $this->setName($name);
        // и выдать его
        $this->echoName();
    }

    function echoName()
    {
        echo "<br>",$this->name;
    }
	
    function setName($name)
    {
        $this->name = $name;
    }
}

Давайте проверим, есть ли различия между $bar1, которая создана с использованием copy = operator и $bar2, которая создана с использованием reference =& operator...

$bar1 = new Foo('set in constructor');
$bar1->echoName();
$globalref[0]->echoName();

/* вывод:
set in constructor
set in constructor
set in constructor */

$bar2 =& new Foo('set in constructor');
$bar2->echoName();
$globalref[1]->echoName();

/* вывод:
set in constructor
set in constructor
set in constructor */

Очевидной разницы нет, но фактически - очень значительная: $bar1 и $globalref[0] это _НЕ_ ссылки, это НЕ одна и та же переменная. Это из-за того, что "new" не возвращает ссылку по умолчанию, а возвращает копию.

Примечание: здесь нет потери производительности (поскольку PHP 4 и более поздние используют подсчёт ссылок) при возвращении копий вместо ссылок. Наоборот, часто намного лучше работать с копиями вместо ссылок, так как создание ссылок занимает некоторое время, а создание копий практически не требует времени (если только они не большие массивы и не изменяются последовательно одна за другой, тогда нужно использовать ссылки для изменения их всех).

Чтобы проверить то, что написано выше, давайте рассмотрим следующий код:

// теперь мы будем изменять имя. что можно ожидать?
// можно ожидать, что $bar1 и $globalref[0] изменят свои имена...
$bar1->setName('set from outside');

// как сказано ранее, это не тот случай.
$bar1->echoName();
$globalref[0]->echoName();

/* вывод:
set from outside
set in constructor */

// давайте посмотрим, что разного есть в $bar2 и в $globalref[1]
$bar2->setName('set from outside');

// к счастью, они не только равны, но это одна и та же переменная
// таким образом, $bar2->name и $globalref[1]->name это также одно и то же
$bar2->echoName();
$globalref[1]->echoName();

/* вывод:
set from outside
set from outside */

Последний пример. Попытайтесь в нём разобраться.

class A
{
    function A($i)
    {
        $this->value = $i;
        // попытайтесь понять, почему ссылка нам здесь не нужна
        $this->b = new B($this);
    }

    function createRef()
    {
        $this->c = new B($this);
    }

    function echoValue()
    {
        echo "<br>","class ",get_class($this),': ',$this->value;
    }
}


class B
{
    function B(&$a)
    {
        $this->a = &$a;
    }

    function echoValue()
    {
        echo "<br>","class ",get_class($this),': ',$this->a->value;
    }
}

// попытайтесь понять, почему использование простой копии здесь даст
// нежелательный результат в строке *-marked
$a =& new A(10);
$a->createRef();

$a->echoValue();
$a->b->echoValue();
$a->c->echoValue();

$a->value = 11;

$a->echoValue();
$a->b->echoValue(); // *
$a->c->echoValue();

/*
output:
class A: 10
class B: 10
class B: 10
class A: 11
class B: 11
class B: 11
*/
Назад Оглавление Вперёд
Магические функции
__sleep и __wakeup
ВверхСсылки. Разъяснения.

Хостинг от uCoz