Smarty (и другие tpl ngins): assign и assign_by_ref - PullRequest
3 голосов
/ 26 апреля 2011

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

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

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

Теперь, что произойдет, если я назначу все свои переменные по ссылке? Я крут с моей точки зрения, что могу изменить массив обратно в контроллер (я все равно не вернусь туда). Также хорошо, если переменная изменяется в движке шаблонов ($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 не возражает против больших массивов, копий и клонов, но с точки зрения производительности и памяти: что «лучше»?

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

UPDATE
Так что PHP использует copy on write ... Люблю это. И объекты всегда указатели. Что происходит, когда вы:

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

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

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

1050 * редактировать *
Интересная визуализация копий, клонов, ссылок и т. Д .: http://www.phpinsider.com/download/PHP5RefsExplained.pdf

Ответы [ 3 ]

6 голосов
/ 26 апреля 2011

PHP использует концепцию, называемую копировать при записи.Т.е. если вы просто сделаете $a = $b, PHP не скопирует все значение $b в $a.Это просто создаст какой-то указатель.(Точнее, и $a, и $b будут указывать на один и тот же 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. Тем не менее, вы правы, что они ведут себя как ссылки - как , потому что для объектов это значение, которое передается, является просто указателем на некоторую другую структуру данных. В большинстве случаев различиемежду передачей по ссылке и поведением, подобным эталонному, не важен, но все же есть разница.

Это было лишь краткое введение в тему. Более подробный анализ можно найтиэтой темы в блоге Сары Големон с надменным заголовком «Вам лгут» .

2 голосов
/ 26 апреля 2011

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

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

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

$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 также влияет.Копирование объектов никогда не происходило.

1 голос
/ 26 апреля 2011

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

...