Smarty (и другие tpn ngins): assign и assign_by_ref

Речь идет не только о Smarty, но я думаю, что большинство движков шаблонов имеют назначенные переменные. Это скорее теоретический вопрос, чем практический. У меня нет прецедента.

Что происходит в PHP, когда вы назначаете большой массив $a другой переменной $b ? PHP копирует массив? Может быть, просто, может быть, внутри он создает указатель. Тогда что происходит, если вы немного измените $a ? $b не следует изменять, потому что no & было использовано для создания $b . Является ли PHP удвоением использования памяти?

Более конкретно: что происходит, когда вы назначаете большой массив из вас Controller ( $a ) для вашего механизма шаблонов ( $tpl->vars['a'] ) и использовать в представлении ( extract в $a )? Была ли память PHP трижды?

Теперь, что произойдет, если я передам все мои переменные по ссылке? Мне классно, что мой взгляд способен изменить массив обратно в контроллер (я все равно не вернусь туда). Это также прекрасно, если переменная изменяется внутри движка templat ( $tpl->vars['a'] ).

Является ли привязка всех варов по ссылке лучше для памяти? Лучше для производительности? Если да: какие-либо шансы на странные нежелательные побочные эффекты?

Потому что люди любят код, а не рассказы:

 // copies $a = array( ... ); $tpl->assign('a', $a); // creates a copy (?) in $tpl->vars['a'] // pointer / by ref $a = array( ... ); $tpl->assign_by_ref('a', $a); // creates a pointer in $tpl->vars['a'] because: function assign_by_ref( $name, &$var ) { $this->vars[$name] = $var; // voila pointer? } 

Я уверен, что PHP не против больших массивов, копий и клонов, но производительность и память мудры: что лучше?

редактировать
Для объектов все это не имеет значения. Объекты всегда, автоматически назначаются по ссылке. А поскольку объекты горячие, может быть, это устаревший вопрос, но мне очень любопытно.

ОБНОВИТЬ
Так что PHP использует copy on write … Любите ее. И объекты всегда являются указателями. Что происходит, когда вы:

 $a = new BigObject; $b = $a; // pointer, right? $b->updateSomethingInternally(); // $b is now changed > what about $a? 

Это вызвало копирование на запись? Или $ a и $ b все еще идентичны (например, в === )?

редактировать
Могу ли я заключить, что назначение ref ref действительно не стоит просто избавить память? PHP сам по себе достаточно умен?

редактировать
Интересная визуализация копии, клонирования, по-ref и т. Д.: Http://www.phpinsider.com/download/PHP5RefsExplained.pdf

Related of "Smarty (и другие tpn ngins): assign и assign_by_ref"

PHP использует концепцию copy при записи. Т.е. если вы просто выполните $a = $b PHP не скопирует все значение $b в $a . Он просто создаст какой-то указатель. (Чтобы быть точнее, как $a и $b refcount на тот же zval, и его refcount будет увеличен.)

Теперь, если изменены значения $a или $b , значение, очевидно, больше не может быть разделено и должно быть скопировано.

Таким образом, если вы не изменяете массив в своем шаблоне, копирование не будет выполнено.

Некоторые дополнительные примечания:

  • Не забывайте пытаться оптимизировать свой код, слепо вставляя ссылки. Часто они будут иметь эффект, противоречащий тому, что вы ожидаете. Пример, чтобы объяснить, почему:

     $a = SOMETHING_BIG; // $a points to a zval with refcount 1 and is_ref 0 $b = $a; // $a and $b both point to a zval with refcount 2 and is_ref 0 $c =& $a; // Now we have a problem: $c can't just point to the same zval // anymore, because that zval has is_ref to 0, but we need one // with is_ref 1. So The zval gets copied. You now have $b // pointing to one zval with refcount 1 and is_ref 0 and $a and // $c pointing to another one with refcount 2 and is_ref 1 

    Так что вопреки тому, что вы хотели, на самом деле произошло. Вместо экономии памяти вы фактически выделяете дополнительные. Часто бывает трудно судить о том, будет ли добавление ссылки улучшаться или ухудшаться, потому что часто трудно отследить все разные переменные, указывающие на один zval (это часто не так просто, как кажется), просто взгляните на примеры функции debug_zval_dump . Итак, действительно, единственный безопасный способ узнать, хороша ли ссылка для производительности или нет, – это фактически профилировать оба варианта.

  • Объекты, как и все остальное, передаются по значению в PHP. Тем не менее вы правы в том, что они ведут себя как ссылочный, потому что с объектами это значение, переданное get, является лишь указателем на какую-либо другую структуру данных. В большинстве случаев различие между отправкой по эталонному и ссылочному поведению не имеет значения, но все же есть разница.

Это было просто краткое введение в эту тему. Вы можете найти более подробный анализ этой темы в блоге Sara Golemon с фразой «Вы лгали» .

Как упоминалось в других ответах, PHP использует copy-on-write. Однако я хочу ответить на эту часть вашего поста:

Объекты всегда, автоматически назначаются по ссылке.

Это не совсем правда. Им присваивается идентификатор, который указывает на объект.

 $a = new stdClass(); $b = $a; // $a and $b now share same identifier $b = 0; // $b no longer contains identifier var_dump($a); // outputs object 

Сравните это с назначением по ссылке:

 $a = new stdClass(); $b =& $a; // $a and $b now share same reference $b = 0; // var_dump($a); // outputs int(0) 

Обновить

В своем правлении вы спрашиваете:

 $a = new BigObject; $b = $a; // pointer, right? $b->updateSomethingInternally(); // $b is now changed > what about $a? 

Это вызвало копирование на запись? Или $ a и $ b все еще идентичны (например, в ===)?

Поскольку $b теперь содержит идентификатор, то есть теперь «указывает» на тот же объект, что и $a , $a также влияет. Не было никакого копирования объектов.

PHP использует copy-on-write при передаче массивов, поэтому дополнительная память не используется до тех пор, пока вы не измените массив. Извините, нет ссылки для резервного копирования этой заявки.