За последние 24 часа нас посетили 58009 программистов и 1845 роботов. Сейчас ищут 1058 программистов ...

Микровопросик

Тема в разделе "PHP для новичков", создана пользователем mirosas, 12 авг 2015.

  1. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    В PHP5 я так понял переменные передаются по значению, объекты по ссылке, но при этом массивы объектов опять передаются по значению? Или в переданном массиве переменные будут переданы по значению, а объекты по ссылке?

    В общем два тупых вопроса от нуба:
    Как передать массив объектов по ссылке?
    Как передать массив объектов по значению?
     
  2. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.128
    Симпатии:
    1.248
    Адрес:
    там-сям
    Пожалуйста оформляй заголовок темы так, чтобы он отражал суть вопроса, а не твою рефлексию по поводу уровня знаний :)

    Куда передаются-то, как параметр? Вот так будет по ссылке:
    Код (PHP):
    1. // Параметр по ссылке
    2. function foo(&$var) 
    3. {
    4. ...
    5. } 
    6. // Присваивание по ссылке
    7. $b =& $a;
    8.  
    Важно знать, что PHP использует "отложенное копирование". Суть: присваивание чего-либо в новую переменную или передача по значению в функцию не означает немедленного дублирования данных. Они копируются в новую область памяти непосредственно перед тем, как будут внесены изменения. … Если вообще будут.

    Если данные только читаются, всё будет работать как если бы копировалась ссылка — очень быстро. Это можно заметить в тестах, замеряющих время выполнения.

    Что касается объектов, то начиная с PHP4, кажется, объект не дублируется при присваивании или передаче в параметр. Он всегда передается по ссылке. Как и в большинстве других ЯП. Если надо продублировать его, придется сделать это явно: есть специальная конструкция clone.

    Добавлено спустя 18 минут 6 секунд:
    Продублировать массив ссылок на те же объекты — достаточно присвоить массив в новую переменную или передать параметром. Объекты при этом не дублируются! Массив новый, а вот ссылки в нём на те же объекты. Забавно, да?

    Продублировать все объекты из массива можно только обработав каждую ссылку через clone. Или через сериализацию/десериализацию.

    Добавлено спустя 6 минут 58 секунд:
    Демка:

    Код (PHP):
    1. <?php
    2.  
    3. $a = [ new StdClass(), new StdClass() ];
    4. $a[0]->foo = 'xxx';
    5. $a[1]->foo = 'yyy';
    6.  
    7. // *** попробуй по _отдельности_ каждый из трёх вариантов ***
    8. //$b = $a;
    9. //$b = [ clone $a[0], clone $a[1] ];
    10. $b = unserialize(serialize($a));
    11.  
    12. $b[1]->foo = 'zzz';
     
  3. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    Интерпретируемый язык программирования что-то еще и оптимизирует оказывается. Зачем если он и так оптимизирует все сделали передачу объектов по ссылке

    Вроде бы с PHP5 объекты по ссылкам передаются.

    Ясно в общем. Я думал есть способы попроще чем каждый объект внутри массива клонировать. Сериализации мне думается должны работать не быстро, хотя для 90% задач думаю подойдет - конструкторы я так понял при сериализации и десериализации не вызываются, деструкторы тоже.

    P.S. не понравилась работа деструкторов в PHP - нужно вызывать unset, иначе деструктор так и не вызывается.
     
  4. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Это не вопрос оптимизации. Есть типы значимые, есть типы ссылочные. Объекты - ссылочные типы. Когда ты создаешь объект и цепляешь его к другому объекту, ты можешь продолжать работать с ним, будучи уверенным, что сейчас ты работаешь именно с тем объектом, что был подцеплен. Так принято во всех языках с ООП.
     
  5. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Ну не во всех. Но многих. В C++ вроде передачу по значению и конструктор копирования ещё не отменили.
     
  6. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    И в этих многих языках с ООП, передача по ссылке объектов, но переменных по значению не порождает ошибки? По своей сути объект сруктуры, контейнер, переменная - это одно и то же - немного странно одни из них передавать по ссылке, другие по значению. Я например люблю поизменять внутри функций переданные в неё параметры.

    Хотелось бы уточнить:
    В PHP передача объектов везде по ссылке, или есть исключения? В функцию находящуюся в глобальном namespace? В функцию объекта? Просто присваивание?
     
  7. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    mirosas, можно же клонировать объект, и делай с ним что хочешь.
     
  8. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    В любом случае, конструкцию clone в PHP используют редко. Это говорит о том, что решение сделать объекты ссылочными, удовлетворяет потребностям программистов. Иначе пришлось бы на каждом шагу втыкать амперсанд.
     
  9. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    +
     
  10. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Ошибки порождает не передача объектов по ссылке, а переменных по значению, а незнание программиста вкупе с непониманием процесса.
    Нет, это не одно и то же. Это совершенно разные вещи. Различия начинаются уже с самых низких уровней, на представлении в памяти машины. Одна из причин, по которой объекты априори передаются по ссылке - тот факт, что не существует лимитов на сложность объектов. Объект может весить хоть 100 метров. А его создание может занимать хоть 50% времени работы скрипта. Если оперировать с ним по ссылке - это ничего не будет стоить. Если по значению - это будет провал.

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

    $obj = func($obj); //не OOP-way
    $obj->func(); // OOP-way

    Объекты сами должны себя править. Сами должны управлять своим содержимым. А содержимое должно быть, в идеале, инкапсулировано от публичного доступа. Оттуда у вас и проблемы - вы просто что-то делаете не так.
     
  11. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    По этой логике массивы переменных должны тоже передаваться по ссылке, а они передаются по значению.
    Имхо - тот же PHP является языком программирования высокого уровня. И переменная, по своей сути и назначению, - такой же объект, как любой другой.


    У меня проблем пока нет - я просто фигачу не разбираясь как что, и оно работает. Но меня такой подход смущает.

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

    $obj->func($obj1,$obj2,$intvalue); - как переделаете в ООП ? В таком виде как здесь в функцию будут отправлены ссылки на объекты в первых двух аргументах, и значение переменной в третьем аргументе. А функция вполне может и поменять obj1 или obj2, что отразится снаружи функции, чего обычно не нужно.
     
  12. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Вы не поняли один тоооонкий момент - это не дискуссия на тему "поменять парадигмы, которые существуют хрен знает сколько лет, или оставить". Это факт. Вы или принимаете его, или нет. Мне от этого, да и всем другим, ни холодно, ни жарко.
    Неразборчивое фигачинье, не обремененное смущением - это уже само по себе проблема. Если не начать замечать ее, можно скатиться в быдлокод. Лучше сразу прививать себе разумное доброе вечное.
    Разумеется. У меня, вот например, в движке, идет гибридизация ООП и процедурного подхода. Но при этом я не пытаюсь работать с объектами по-процедурному, а с процедурами по-объектному. Каждая из парадигм используется правильно. И только там, где именно она нужна.
    Очень просто. Внутри func() должно идти обращение к соответственным методам $obj1 и $obj2. Которые сами должны менять то, что у них внутри. Обращаться к данным объектов напрямую - плохо. Это прокатывает только до тех пор, пока их присвоение и получение не имеют логики сложнее, чем "=" и "return".

    И нет, массивы не должны вести себя как объекты. Массив - единая структура в памяти. Объект - нет. Массив - это именно значение. У объекта нет понятия "значение". Объект - это набор свойств, методов, обработчиков и собственный контекст выполнения. Объект это объект, а не просто хранилище значений. Если вам нужны просто n-мерные массивы, лучше используйте их.
     
  13. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    Проблема в том, что эти методы вполне могут изменить сам объект.

    Где их по общепринятым нормам клонируют? Внутри метода? Или перед вызовом метода? Если хоть там, хоть там - это вызовет неопределенность и потенциальные места для ошибок.

    Хотелось бы по конструктору клонирования сразу спросить - как из него обращаться к данным находящимся в старом объекте, и как к данным находящимся в новом объекте? Например я при клонировании хочу в старом объекте изменить переменную $kol_copies++;, а в новом объекте переменной $kol_copies=0;
     
  14. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    Из конструктора клонирования никуда обращаться не надо. Вы по-моему запутались слегка, читая все подряд.

    Это делается примерно так:
    Код (PHP):
    1. class A {
    2.  
    3.     private $property = "";
    4.  
    5.     
    6.     function __construct($property="") {
    7.         $this->setProperty($property);
    8.     }
    9.     
    10.     public function setProperty($property){
    11.         //минимальный код
    12.         $this->property = $property;
    13.     }
    14.     
    15.     public function getProperty(){
    16.         return $this->property;
    17.     }
    18.  
    19. }
    20. $class = new A(); //создаем объект
    21. $class->setProperty('Значение');//инициализируем свойство объекта
    22. $clone = clone $class;//Клонируем. Теперь мы имеем точную копию объекта $class
    23. //Склонированный объект имеет те же данные, свойства, методы что и объект $class, но это пока..
    24. //Чтобы убедиться это так, выведем значение свойства склонированного объекта и 
    25. //главного объекта
    26. echo "отладка \'объект \$class\': ".$class->getProperty();
    27. echo "<br>";
    28. echo "отладка \'объект \$clone\': ".$clone->getProperty();
    29. //Теперь переустановим значение свойства склонированного объекта
    30. //и выведем опят на экран
    31.  
    32. $clone->setProperty('Новое значение');
    33. echo "<br>";
    34. echo "<br>";
    35. echo "После изменения данных склонированного объекта";
    36. echo "<br><br>";
    37. echo "отладка \'объект \$class\': ".$class->getProperty();
    38. echo "<br>";
    39. echo "отладка \'объект \$clone\': ".$clone->getProperty();
    40.  
    41. //Объекты $class и $clone  никак не связаны   
    Добавлено спустя 52 секунды:
    выполните этот код у себя
     
  15. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Для решения этой проблемы существует ArrayObject.
    Вот не обязательно. Первые версии PHP разве были низкоуровневыми? Уровень языка символизирует его отдаленность от машинных кодов. Это не обязательно уровень абстракции.
    Главный тип данных в PHP это string. Он создан для обработки текста. В нём всё, что угодно, превращается в строку на раз. Даже массив, движок будет плеваться, но превратит в тупое слово Array с потерей всех данных. А для объектов существует магический метод __toString().
    В PHP не нужно открывать Главную Функцию, чтобы код начал откуда-то выполняться. Он начинает выполняться с первого открывающего дескриптора, хоть внутри mp3-рингтона.
    Поэтому ООП в PHP не надо воспринимать слишком всерьез.
     
  16. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    Ну а если хочется? На плюсах например вполне можно обращаться внутри конструктора копирования как к новому, так и к старому объекту.

    Мм.. ну я как бы и прочитав все понял, чего так длинно))). Бывают ситуации, что клон по значениям и клон по логике это не одно и то же. Например в объекте есть свойство $uniquire_id. И при создании клона по логике этот уникальный идентификатор должен стать уже другим. Я так понял в PHP можно сделать клон по значению, но клон по логике далеко не всегда.

    )))

    Добавлено спустя 11 минут 43 секунды:
    Подскажите, как по нормам красивого кодинга на ПХП. Где в таком коде нужно вызывать clone -

    Так:
    Код (PHP):
    1. function func($obj)
    2. {
    3.     $obj2=clone $obj;
    4.     $obj2->update();
    5.     return $obj2;
    6. }
    7.  
    8. $a = new A();
    9. echo (string)func($a);
    10. echo (string)$a;
    11.  
    Или так:
    Код (PHP):
    1. function func($obj)
    2. {
    3.     $obj->update();
    4.     return $obj;
    5. }
    6.  
    7. $a = new A();
    8. echo (string)func(clone($a));
    9. echo (string)$a;
    10.  
    ?

    Добавлено спустя 12 минут 46 секунд:
    ))) Сегодня как раз для каких-то тестов его использовал))

    PHP, JavaScript, SQL и другой код пишите внутри тегов
    Код ( (Unknown Language)):
    1. [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
     
  17. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    Это уже зависит от установок, чего ожидаете от функции. Если вы ожидаете получить от функции склонированный объект то первый вариант,
    а если получить главный объект то второй вариант.

    К старому остается обращаться как обычно, а вот склонированного (нового) данные можно менять еще в методе __clone который должен быть определен в в копируемом классе.
    Код (PHP):
    1.    public function __clone() {
    2.         $this->setProperty('Новое значение');
    3.         
    4.     } 
     
  18. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    Хм.. Изучаю сейчас Javascript - там оказывается переменные и объекты одно и то же)). У переменных есть методы)). Хорошо придумано.

    Добавлено спустя 2 минуты 38 секунд:
    Как обычно это как? (внутри конструктора клон к старому). Тоесть $this-> указывает на уже новый объект. Ясненько).
     
  19. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.631
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    т.е. не нашел способа из магического метода __clone() обратится к копируемому объекту.
    Разве что вот так.

    Код (PHP):
    1. class A {
    2.  
    3.     public $object1;
    4.     public $object2;
    5.  
    6.     public function __clone() {
    7.         $this->object1->var = 'Первый объект';
    8.         $this->object2 = clone $this->object2;
    9.         $this->object2->var = 'Втрой объект';
    10.     }
    11.  
    12. }
    13.  
    14. class B {
    15.  
    16.     public $var = 'dd';
    17.     private static $instance;
    18.  
    19.     public function __construct() {
    20.        
    21.     }
    22.      public static function getInstance() {
    23.         if (empty(self::$instance)) {
    24.             self::$instance = new self();
    25.         }
    26.         return self::$instance;
    27.     }
    28.  
    29. }
    30.  
    31. $obj1 = new A();
    32. $obj1->object1 = B::getInstance();
    33. $obj1->object2 = B::getInstance();
    34.  
    35. $obj2 = clone $obj1;
    36.  
    37. //в итоге имеем два разных объекта класса B при том, 
    38. //можем управлять содержимым первого и второго объекта из магического метода
    39.  
    40. echo $obj1->object1->var . "<br>";
    41. echo $obj2->object2->var;
    42. echo "<pre>";
    43. var_dump($obj1);
    44. var_dump($obj2);
    Добавлено спустя 32 минуты 52 секунды:
    Чтобы убедиться что $this->object1 и $this->object2 один и тот же объект, можете закомментировать две первые строчки кода в методе __clone() и вы увидите что значение которое переустанавливается для второго объекта переустанавилось и для первого.
    Так же var_dump() покажет что это один и тот же объект
     
  20. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Я так понял доки, что при клонировании php сначала создаёт точную копию объекта, а потом вызывает __clone() у нового объекта. Поэтому вот это верный подход
    Код (PHP):
    1. public function __clone() {
    2. $this->object2 = clone $this->object2;
    3.  
     
  21. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Нет, не одно. Просто там нет ничего, кроме объектов. Функции, к слову, тоже объекты. И тоже могут иметь свои методы и свойства.
     
  22. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    Провел пару тестов. В общем с конструктором клонирования оказались интересные фокусы.

    1. Сперва PHP делает копию объекта. Но делает её по особому. Это как бы не совсем копия объекта. Тоесть тупо вызывать clone и не париться не выйдет. А не выйдет оно потому, что объекты находящиеся внутри склонированного объекта клонироваться оказывается не будут, вместо этого будет произведено присваивание по ссылке.
    - Для PersonalHomePage жесткова-то.


    2. Прочитать родительский объект проблем в общем-то нет. Записать в новый объект тоже нет проблем.

    По настоящему ориентированный на объекты язык))
     
  23. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    С каким-то извращением вместо классов
     
  24. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    ))).
     
  25. mirosas

    mirosas Активный пользователь

    С нами с:
    17 июл 2015
    Сообщения:
    236
    Симпатии:
    5
    Хм.. в javascript оказывается такие же фокусы - объекты по ссылке, а примитивы по значению.

    Интересно, за ради чего в php5 сделали передачу по ссылке, а не по значению как было в php3. Производительность - во первых php не тот язык, чтобы жертвовать удобством ради производительности, во вторых интерпретатор, как говорит artoodetoo, все-равно передачу по значениям оптимизирует, и где его можно заменить на передачу по ссылке - заменяет. Потенциально передача по ссылке может порождать ошибки, и требует держания в голове много большей информации по коду чтобы такие ошибки не возникали, либо отказу от записи в ранее созданные объекты, что удлиняет код, а так же уменьшает производительность.

    Странно что в php конструктор клонирования по умолчанию входящие в объект объекты не клонирует, а копирует ссылку - в java так же? Где-то я читал что а PHP5 ООП модель почти полностью склонировали с Java.