В PHP5 я так понял переменные передаются по значению, объекты по ссылке, но при этом массивы объектов опять передаются по значению? Или в переданном массиве переменные будут переданы по значению, а объекты по ссылке? В общем два тупых вопроса от нуба: Как передать массив объектов по ссылке? Как передать массив объектов по значению?
Пожалуйста оформляй заголовок темы так, чтобы он отражал суть вопроса, а не твою рефлексию по поводу уровня знаний Куда передаются-то, как параметр? Вот так будет по ссылке: Код (PHP): // Параметр по ссылке function foo(&$var) { ... } // Присваивание по ссылке $b =& $a; Важно знать, что PHP использует "отложенное копирование". Суть: присваивание чего-либо в новую переменную или передача по значению в функцию не означает немедленного дублирования данных. Они копируются в новую область памяти непосредственно перед тем, как будут внесены изменения. … Если вообще будут. Если данные только читаются, всё будет работать как если бы копировалась ссылка — очень быстро. Это можно заметить в тестах, замеряющих время выполнения. Что касается объектов, то начиная с PHP4, кажется, объект не дублируется при присваивании или передаче в параметр. Он всегда передается по ссылке. Как и в большинстве других ЯП. Если надо продублировать его, придется сделать это явно: есть специальная конструкция clone. Добавлено спустя 18 минут 6 секунд: Продублировать массив ссылок на те же объекты — достаточно присвоить массив в новую переменную или передать параметром. Объекты при этом не дублируются! Массив новый, а вот ссылки в нём на те же объекты. Забавно, да? Продублировать все объекты из массива можно только обработав каждую ссылку через clone. Или через сериализацию/десериализацию. Добавлено спустя 6 минут 58 секунд: Демка: Код (PHP): <?php $a = [ new StdClass(), new StdClass() ]; $a[0]->foo = 'xxx'; $a[1]->foo = 'yyy'; // *** попробуй по _отдельности_ каждый из трёх вариантов *** //$b = $a; //$b = [ clone $a[0], clone $a[1] ]; $b = unserialize(serialize($a)); $b[1]->foo = 'zzz'; var_dump($a); var_dump($b);
Интерпретируемый язык программирования что-то еще и оптимизирует оказывается. Зачем если он и так оптимизирует все сделали передачу объектов по ссылке Вроде бы с PHP5 объекты по ссылкам передаются. Ясно в общем. Я думал есть способы попроще чем каждый объект внутри массива клонировать. Сериализации мне думается должны работать не быстро, хотя для 90% задач думаю подойдет - конструкторы я так понял при сериализации и десериализации не вызываются, деструкторы тоже. P.S. не понравилась работа деструкторов в PHP - нужно вызывать unset, иначе деструктор так и не вызывается.
Это не вопрос оптимизации. Есть типы значимые, есть типы ссылочные. Объекты - ссылочные типы. Когда ты создаешь объект и цепляешь его к другому объекту, ты можешь продолжать работать с ним, будучи уверенным, что сейчас ты работаешь именно с тем объектом, что был подцеплен. Так принято во всех языках с ООП.
Ну не во всех. Но многих. В C++ вроде передачу по значению и конструктор копирования ещё не отменили.
И в этих многих языках с ООП, передача по ссылке объектов, но переменных по значению не порождает ошибки? По своей сути объект сруктуры, контейнер, переменная - это одно и то же - немного странно одни из них передавать по ссылке, другие по значению. Я например люблю поизменять внутри функций переданные в неё параметры. Хотелось бы уточнить: В PHP передача объектов везде по ссылке, или есть исключения? В функцию находящуюся в глобальном namespace? В функцию объекта? Просто присваивание?
В любом случае, конструкцию clone в PHP используют редко. Это говорит о том, что решение сделать объекты ссылочными, удовлетворяет потребностям программистов. Иначе пришлось бы на каждом шагу втыкать амперсанд.
Ошибки порождает не передача объектов по ссылке, а переменных по значению, а незнание программиста вкупе с непониманием процесса. Нет, это не одно и то же. Это совершенно разные вещи. Различия начинаются уже с самых низких уровней, на представлении в памяти машины. Одна из причин, по которой объекты априори передаются по ссылке - тот факт, что не существует лимитов на сложность объектов. Объект может весить хоть 100 метров. А его создание может занимать хоть 50% времени работы скрипта. Если оперировать с ним по ссылке - это ничего не будет стоить. Если по значению - это будет провал. И да, если вы берете объекты и передаете в левые функции, которые что-то в них меняют, значит вы попросту не понимаете, пока что, ООП-парадигмы, того, зачем нужны объекты вообще, и как с ними работать. Вы их используете просто как древовидные переменные, походу. $obj = func($obj); //не OOP-way $obj->func(); // OOP-way Объекты сами должны себя править. Сами должны управлять своим содержимым. А содержимое должно быть, в идеале, инкапсулировано от публичного доступа. Оттуда у вас и проблемы - вы просто что-то делаете не так.
По этой логике массивы переменных должны тоже передаваться по ссылке, а они передаются по значению. Имхо - тот же PHP является языком программирования высокого уровня. И переменная, по своей сути и назначению, - такой же объект, как любой другой. У меня проблем пока нет - я просто фигачу не разбираясь как что, и оно работает. Но меня такой подход смущает. Что-то мне думается даже в популярных фреймворках, далеко не во всех, используется чистый ООП, что уж говорить о целесообразности такого подхода в единичных продуктах. Мне самому более нравится объектный подход, без ориентированности. $obj->func($obj1,$obj2,$intvalue); - как переделаете в ООП ? В таком виде как здесь в функцию будут отправлены ссылки на объекты в первых двух аргументах, и значение переменной в третьем аргументе. А функция вполне может и поменять obj1 или obj2, что отразится снаружи функции, чего обычно не нужно.
Вы не поняли один тоооонкий момент - это не дискуссия на тему "поменять парадигмы, которые существуют хрен знает сколько лет, или оставить". Это факт. Вы или принимаете его, или нет. Мне от этого, да и всем другим, ни холодно, ни жарко. Неразборчивое фигачинье, не обремененное смущением - это уже само по себе проблема. Если не начать замечать ее, можно скатиться в быдлокод. Лучше сразу прививать себе разумное доброе вечное. Разумеется. У меня, вот например, в движке, идет гибридизация ООП и процедурного подхода. Но при этом я не пытаюсь работать с объектами по-процедурному, а с процедурами по-объектному. Каждая из парадигм используется правильно. И только там, где именно она нужна. Очень просто. Внутри func() должно идти обращение к соответственным методам $obj1 и $obj2. Которые сами должны менять то, что у них внутри. Обращаться к данным объектов напрямую - плохо. Это прокатывает только до тех пор, пока их присвоение и получение не имеют логики сложнее, чем "=" и "return". И нет, массивы не должны вести себя как объекты. Массив - единая структура в памяти. Объект - нет. Массив - это именно значение. У объекта нет понятия "значение". Объект - это набор свойств, методов, обработчиков и собственный контекст выполнения. Объект это объект, а не просто хранилище значений. Если вам нужны просто n-мерные массивы, лучше используйте их.
Проблема в том, что эти методы вполне могут изменить сам объект. Где их по общепринятым нормам клонируют? Внутри метода? Или перед вызовом метода? Если хоть там, хоть там - это вызовет неопределенность и потенциальные места для ошибок. Хотелось бы по конструктору клонирования сразу спросить - как из него обращаться к данным находящимся в старом объекте, и как к данным находящимся в новом объекте? Например я при клонировании хочу в старом объекте изменить переменную $kol_copies++;, а в новом объекте переменной $kol_copies=0;
Из конструктора клонирования никуда обращаться не надо. Вы по-моему запутались слегка, читая все подряд. Это делается примерно так: Код (PHP): class A { private $property = ""; function __construct($property="") { $this->setProperty($property); } public function setProperty($property){ //минимальный код $this->property = $property; } public function getProperty(){ return $this->property; } } $class = new A(); //создаем объект $class->setProperty('Значение');//инициализируем свойство объекта $clone = clone $class;//Клонируем. Теперь мы имеем точную копию объекта $class //Склонированный объект имеет те же данные, свойства, методы что и объект $class, но это пока.. //Чтобы убедиться это так, выведем значение свойства склонированного объекта и //главного объекта echo "отладка \'объект \$class\': ".$class->getProperty(); echo "<br>"; echo "отладка \'объект \$clone\': ".$clone->getProperty(); //Теперь переустановим значение свойства склонированного объекта //и выведем опят на экран $clone->setProperty('Новое значение'); echo "<br>"; echo "<br>"; echo "После изменения данных склонированного объекта"; echo "<br><br>"; echo "отладка \'объект \$class\': ".$class->getProperty(); echo "<br>"; echo "отладка \'объект \$clone\': ".$clone->getProperty(); //Объекты $class и $clone никак не связаны Добавлено спустя 52 секунды: выполните этот код у себя
Для решения этой проблемы существует ArrayObject. Вот не обязательно. Первые версии PHP разве были низкоуровневыми? Уровень языка символизирует его отдаленность от машинных кодов. Это не обязательно уровень абстракции. Главный тип данных в PHP это string. Он создан для обработки текста. В нём всё, что угодно, превращается в строку на раз. Даже массив, движок будет плеваться, но превратит в тупое слово Array с потерей всех данных. А для объектов существует магический метод __toString(). В PHP не нужно открывать Главную Функцию, чтобы код начал откуда-то выполняться. Он начинает выполняться с первого открывающего дескриптора, хоть внутри mp3-рингтона. Поэтому ООП в PHP не надо воспринимать слишком всерьез.
Ну а если хочется? На плюсах например вполне можно обращаться внутри конструктора копирования как к новому, так и к старому объекту. Мм.. ну я как бы и прочитав все понял, чего так длинно))). Бывают ситуации, что клон по значениям и клон по логике это не одно и то же. Например в объекте есть свойство $uniquire_id. И при создании клона по логике этот уникальный идентификатор должен стать уже другим. Я так понял в PHP можно сделать клон по значению, но клон по логике далеко не всегда. ))) Добавлено спустя 11 минут 43 секунды: Подскажите, как по нормам красивого кодинга на ПХП. Где в таком коде нужно вызывать clone - Так: Код (PHP): function func($obj) { $obj2=clone $obj; $obj2->update(); return $obj2; } $a = new A(); echo (string)func($a); echo (string)$a; Или так: Код (PHP): function func($obj) { $obj->update(); return $obj; } $a = new A(); echo (string)func(clone($a)); echo (string)$a; ? Добавлено спустя 12 минут 46 секунд: ))) Сегодня как раз для каких-то тестов его использовал)) PHP, JavaScript, SQL и другой код пишите внутри тегов Код ( (Unknown Language)): [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
Это уже зависит от установок, чего ожидаете от функции. Если вы ожидаете получить от функции склонированный объект то первый вариант, а если получить главный объект то второй вариант. К старому остается обращаться как обычно, а вот склонированного (нового) данные можно менять еще в методе __clone который должен быть определен в в копируемом классе. Код (PHP): public function __clone() { $this->setProperty('Новое значение'); }
Хм.. Изучаю сейчас Javascript - там оказывается переменные и объекты одно и то же)). У переменных есть методы)). Хорошо придумано. Добавлено спустя 2 минуты 38 секунд: Как обычно это как? (внутри конструктора клон к старому). Тоесть $this-> указывает на уже новый объект. Ясненько).
т.е. не нашел способа из магического метода __clone() обратится к копируемому объекту. Разве что вот так. Код (PHP): class A { public $object1; public $object2; public function __clone() { $this->object1->var = 'Первый объект'; $this->object2 = clone $this->object2; $this->object2->var = 'Втрой объект'; } } class B { public $var = 'dd'; private static $instance; public function __construct() { } public static function getInstance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } $obj1 = new A(); $obj1->object1 = B::getInstance(); $obj1->object2 = B::getInstance(); $obj2 = clone $obj1; //в итоге имеем два разных объекта класса B при том, //можем управлять содержимым первого и второго объекта из магического метода echo $obj1->object1->var . "<br>"; echo $obj2->object2->var; echo "<pre>"; var_dump($obj1); var_dump($obj2); Добавлено спустя 32 минуты 52 секунды: Чтобы убедиться что $this->object1 и $this->object2 один и тот же объект, можете закомментировать две первые строчки кода в методе __clone() и вы увидите что значение которое переустанавливается для второго объекта переустанавилось и для первого. Так же var_dump() покажет что это один и тот же объект
Я так понял доки, что при клонировании php сначала создаёт точную копию объекта, а потом вызывает __clone() у нового объекта. Поэтому вот это верный подход Код (PHP): public function __clone() { $this->object2 = clone $this->object2;
Нет, не одно. Просто там нет ничего, кроме объектов. Функции, к слову, тоже объекты. И тоже могут иметь свои методы и свойства.
Провел пару тестов. В общем с конструктором клонирования оказались интересные фокусы. 1. Сперва PHP делает копию объекта. Но делает её по особому. Это как бы не совсем копия объекта. Тоесть тупо вызывать clone и не париться не выйдет. А не выйдет оно потому, что объекты находящиеся внутри склонированного объекта клонироваться оказывается не будут, вместо этого будет произведено присваивание по ссылке. - Для PersonalHomePage жесткова-то. 2. Прочитать родительский объект проблем в общем-то нет. Записать в новый объект тоже нет проблем. По настоящему ориентированный на объекты язык))
Хм.. в javascript оказывается такие же фокусы - объекты по ссылке, а примитивы по значению. Интересно, за ради чего в php5 сделали передачу по ссылке, а не по значению как было в php3. Производительность - во первых php не тот язык, чтобы жертвовать удобством ради производительности, во вторых интерпретатор, как говорит artoodetoo, все-равно передачу по значениям оптимизирует, и где его можно заменить на передачу по ссылке - заменяет. Потенциально передача по ссылке может порождать ошибки, и требует держания в голове много большей информации по коду чтобы такие ошибки не возникали, либо отказу от записи в ранее созданные объекты, что удлиняет код, а так же уменьшает производительность. Странно что в php конструктор клонирования по умолчанию входящие в объект объекты не клонирует, а копирует ссылку - в java так же? Где-то я читал что а PHP5 ООП модель почти полностью склонировали с Java.