Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Для профи > References


Автор: SwordOfDeath 5.6.2011, 23:32
Привет, 
Помогите разобраться как работает механизм by reference в PHP... Знаком с указателями в C...
Прочитав документацию, коментарии и объяснения все равно не могу понять как этот механизм работает в PHP.

Пишу Double Linked List... Ну и нужен "byreference" и работа с объектами по указателю(ссылке). А также динамическое создание объектов в списке... и соответственно динамическое освобождение...

Где-то проскакивает информация что reference в PHP это ссылки на данные... а где-то что reference это переменные указывающие на ссылки на данные. 

Вот мой класс:
Код
<?php
class ListNode{
    public $data;
    public $prev;
    public $next;
    
    function __construct(&$data){
        $this->data = &$data;
        $this->next = NULL;
        $this->prev = NULL;
    }
}
 
class LinkedList{
    public $firstNode;
    public $lastNode;
    public $count;
    public $nullref;
    
    function __construct(){
        $this->firstNode = NULL;
        $this->lastNode = NULL;
        $this->nullref = NULL;
        $this->count = 0;
    }
    
    public function prepend(&$data){
        $link = new ListNode(&$data);
        if($this->firstNode == NULL){
            $this->lastNode = &$link;
        } else {
            $link->next = &$this->firstNode;
            $this->firstNode->prev = &$link;
        }
        $this->firstNode = &$link;
        $this->count++;
    }
    
    public function append(&$data){
        $link = new ListNode(&$data);
        if($this->lastNode == NULL)
        {
            $this->firstNode = &$link;
        } else {
            $this->lastNode->next = &$link;
            $link->prev = &$this->lastNode;
        }
        $this->lastNode = &$link;
        $this->count++;
    }
    
    public function &deleteFirstNode(){
        if(!$this->count) return $this->nullref;
        $node = &$this->firstNode;
        if($node->next == NULL){
            $this->firstNode = NULL;
            $this->lastNode = NULL;
        } else {
            $this->firstNode = &$node->next;
            $this->firstNode->prev = NULL;
        }
        $this->count--;
        return $node;
    }
    
    public function &deleteLastNode(){
        if(!$this->count) return $this->nullref;
        $node = &$this->lastNode;
        if($node->prev == NULL){
            $this->firstNode = NULL;
            $this->lastNode = NULL;            
        } else {
            $this->lastNode = &$node->prev;
            $this->lastNode->next = NULL;
        }
        $this->count--;
        return $node;
    }
    
    public function &deleteNode(&$node){
        if(!$this->count) return $this->nullref;
        
        if($node->prev == NULL && $node->next == NULL && $this->firstNode == $node){
            $this->firstNode = NULL;
            $this->lastNode = NULL;
        } else if($node->prev != NULL && $node->next != NULL){
            $node->prev->next = &$node->next;
            $node->next->prev = &$node->prev;    
        } else if($node->prev == NULL && $this->firstNode == $node){
            $this->firstNode = &$node->next;
            $this->firstNode->prev = NULL;
        } else if($node->next == NULL && $this->lastNode == $node){
            $this->lastNode = &$node->prev;
            $this->lastNode->next = NULL;
        } else {
            return NULL;
        }
        $this->count--;
        return $node;
    }    
}
?>


В общем я пришел в выводу что везде где мне не требуется копирование нужно ставить амперсанд. Но потом просто ужаснулся от количества амперсандов в коде...
Код кажется работает но я буду очень благодарен если мне кто-то поможет разобраться и сделать все по уму, а не в слепую лепить byref!

PS: Я так понимаю сборщик мусора автоматом почистит данные которые остались без ссылок?

Автор: Absinthe 8.6.2011, 23:38
Цитата

Помогите разобраться как работает механизм by reference в PHP... 


Привет. Мой совет - купи хорошую книжку по основам и прочитай.
Кратко:
1) по значению копируются простые типы и массивы. По ссылке - объекты.
2) Т.е. если ты передаешь объект - то & не нужно
3) При передачи массива не происходит выделение лишних ресурсов - они выделяются при изменении массива. Так что не беспокойся.
4) Если ты передаешь по ссылке переменну типа строка или число, то у тебя наверняка ошибка проектирования.

Так что количество & в хорошем коде стремитс к нулю.

Автор: SwordOfDeath 9.6.2011, 23:54
Цитата(Absinthe @  8.6.2011,  23:38 Найти цитируемый пост)
4) Если ты передаешь по ссылке переменну типа строка или число, то у тебя наверняка ошибка проектирования.

Эм... А в чем проблема? Так ведь и должно быть.... Мой клас не должен ничего копировать будь то строки или числа...

Цитата(Absinthe @  8.6.2011,  23:38 Найти цитируемый пост)
2) Т.е. если ты передаешь объект - то & не нужно

А при присваивании или возврате?

В моем конкретном случае работаю со списком объектов... Таким образом убрав & в описании параметров функции копирования не будет происходить и переменная будет указывать на изначальные данные?

Автор: Absinthe 10.6.2011, 10:06
Цитата

Эм... А в чем проблема? Так ведь и должно быть.... Мой клас не должен ничего копировать будь то строки или числа...
 Копирование происходит при изменении, так что если не изменялось - не копируется.
А если тебе надо как-то внутри изменить число, которое передали - то мне твой код не нравится.
Хочешь менять что-то - то возвращай такое значение, или внеси его как переменную класса.

Цитата

А при присваивании или возврате?
 По ссылке всегда в случае объекта.

Автор: SwordOfDeath 10.6.2011, 12:37
Спасибо огромное за пояснения...
В итоге получается что нужно все оставлять как есть... Потому что все мои byref дублируют стандартное поведение php и убирают "copy on write" что мне и нужно так как в объектах мне нужно менять ссылку на предыдущий и следующий...
Конечно можно было бы убрать byref от хранимых в списке данных так как я их не меняю... но по моему лучше оставить потому что это дает читающему человеку понимание что происходит byref и не нужно сильно задумываться о внутренностях php с её "copy on write" и различным поведением для разных типов данных.

Автор: Absinthe 10.6.2011, 14:31
Цитата

но по моему лучше оставить потому что это дает читающему человеку понимание что происходит byref и не нужно
 Подразумевается, что читающий человек знает основы языка.
И такие вещи затрудняют чтение, акцентируя на себе внимание и читающий будет ожидать какой-то финт.

Автор: SwordOfDeath 10.6.2011, 18:44
Ну вот мне пришлось прибегнуть к помощи форума даже после прочтения мануала и активного гугления... А на форуме в ветке для профи тему прочитало больше 70 человек перед тем как что-то откомментировать... Это наталкивает на мысль что читающий должен быть чуть более обознан в тонкостях php...
Да и программистов на php больше волнует простота и красота кода чем его эффективность... В данном случае этот класс написан для оптимизации... Что само по себе странно ведь данный функционал должен быть в самом языке... с красивым итератором для foreach итд...

Согласен что человека который имеет солидный опыт программирования на php такая запись может немного сбить с толку...
Но ведь byref он и в африке byref... А все эти скрытые копирования и хитрые условия по типам вот это реально сбивает с толку... По крайней мере меня так точно...

Спасибо за помощь! 

Автор: Absinthe 10.6.2011, 22:02
Цитата

Это наталкивает на мысль что читающий должен быть чуть более обознан в тонкостях php...
 Я еще раз повторю. Это не тонкости. Это самые основы и все их знают.


Цитата

Да и программистов на php больше волнует простота и красота кода чем его эффективность... 
 Не путай программистов и праздных студентов.

Цитата

Что само по себе странно ведь данный функционал должен быть в самом языке... с красивым итератором для foreach итд...
 SPL.

Цитата

Но ведь byref он и в африке byref... А все эти скрытые копирования и хитрые условия по типам вот это реально сбивает с толку... По крайней мере меня так точно...
 После 1-2 месяцев PHP основы как-то сами собой постигнутся в достаточном объеме.

Автор: dark_religion 18.6.2011, 21:04
я вопроса не понял?)))  что именно не получается? 

Только в пхп списки так не работают в пхп не существует указателей на объекты)) Вот вычитал:

As of PHP 5.3, PHP's SPL extension contains the 'SplDoublyLinkedList' class that can be used to implement Deque datastructures. Previously to make a Deque structure the array functions array_shift/unshift/pop/push had to be used instead.

По руски говоря, поддержка  списков в php только в виде масивов, начиная с версии 5.3 есть класс SplDoublyLinkedList

http://php.net/manual/en/class.spldoublylinkedlist.php

А типо создание своего списка по моему теряет смысл) так как пхп не поддерживает той функциональности, что к примеру C++ ) то есть если вы и сделаете список) он смысла иметь не будет) 

Может я не прав, но немогу найти, что бы делали списки в php )) мы же не самые умные) раз не делают значит есть на то причина)

Еще вот есть класс http://php.net/manual/en/class.splqueue.php

Автор: dark_religion 18.6.2011, 22:31
Цитата(Absinthe @  10.6.2011,  22:02 Найти цитируемый пост)
Не путай программистов и праздных студентов.


Хотел бы я посмотреть на вашу реализацию списка на Php продимонстрируйте всем ваши нестуденческие навыки самый простой пример:

Односвязный список. реализовать функцию push и добавить с помощью нее 5 елементов. И вывести содержимое объекта на экран, осилите?) 
Ато вы нас тут всех студентами обозвали. Продемонстируйте нам ваши супер навыки! Хоть одного балабола с ответами изучайте основы php удастся поймать за язык)) Встроеные классы в php можете нам не демонстрировать. Функция push должна быть полностью реализованна вами. 

Автор: Absinthe 21.6.2011, 23:18
Цитата

Хотел бы я посмотреть на вашу реализацию списка на Php продимонстрируйте всем ваши нестуденческие навыки самый простой пример:

Односвязный список. реализовать функцию push и добавить с помощью нее 5 елементов. И вывести содержимое объекта на экран, осилите?) 
Ато вы нас тут всех студентами обозвали. Продемонстируйте нам ваши супер навыки! Хоть одного балабола с ответами изучайте основы php удастся поймать за язык)) Встроеные классы в php можете нам не демонстрировать. Функция push должна быть полностью реализованна вами. 
 Я думаю, что данный вопрос неуместен в теме, его было бы правильнее задать в разделе о работе.
Ну и в таких случаях принято указывать вознаграждение.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)