Re: [SMARTY-DEV] Re: [SMARTY] Re:[SMARTY-DEV]$smarty.session.object doesn't work in 2.5.0
| From: | Wom.bat | Date: | Tue, 15 Apr 2003 19:22:59 +0000 |
| Subject: | Re: [SMARTY-DEV] Re: [SMARTY] Re:[SMARTY-DEV]$smarty.session.object doesn't work in 2.5.0 | ||
| References: | 1 2 3 4 5 6 | Groups: | php.smarty.dev |
| Request: | Send a blank email to php-smarty-dev+get-1165@lists.php.net to get a copy of this message | ||
> Right, but Smarty's method of variable assignement always makes a copy
> regardless of the data type.
As far as I can see that, Smarty does
$this->_tpl_vars[$tpl_var] = $value;
This creates _definitely_ a reference to $value, as long as $value is not
altered. Actually, it is not possible to force the copying of a variable.
Always creating references as long as the assigned variables are not altered
is a feature which has been introduced with PHP4 in order to avoid
unnecessary overhead.
Read http://www.zend.com/zend/art/ref-count.php,
especially on from
paragraph "What is variable counting".
You may also look this up in the PHP source, 4.3.1, zend_execute.c, function
zend_assign_to_variable, lines 413-487 (explanation follows below):
if (PZVAL_IS_REF(variable_ptr)) {
if (variable_ptr!=value) {
short refcount=variable_ptr->refcount;
zval garbage;
if (type!=IS_TMP_VAR) {
value->refcount++;
}
garbage = *variable_ptr;
*variable_ptr = *value;
variable_ptr->refcount = refcount;
variable_ptr->is_ref = 1;
if (type!=IS_TMP_VAR) {
zendi_zval_copy_ctor(*variable_ptr);
value->refcount--;
}
zendi_zval_dtor(garbage);
}
} else {
variable_ptr->refcount--;
if (variable_ptr->refcount==0) {
switch (type) {
case IS_VAR:
/* break missing intentionally */
case IS_CONST:
if (variable_ptr==value) {
variable_ptr->refcount++;
} else if (PZVAL_IS_REF(value)) {
zval tmp;
tmp = *value;
zval_copy_ctor(&tmp);
tmp.refcount=1;
zendi_zval_dtor(*variable_ptr);
*variable_ptr = tmp;
} else {
value->refcount++;
zendi_zval_dtor(*variable_ptr);
safe_free_zval_ptr(variable_ptr);
*variable_ptr_ptr = value;
}
break;
case IS_TMP_VAR:
zendi_zval_dtor(*variable_ptr);
value->refcount=1;
*variable_ptr = *value;
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
} else { /* we need to split */
switch (type) {
case IS_VAR:
/* break missing intentionally */
case IS_CONST:
if (PZVAL_IS_REF(value) && value->refcount > 0) {
ALLOC_ZVAL(variable_ptr);
*variable_ptr_ptr = variable_ptr;
*variable_ptr = *value;
zval_copy_ctor(variable_ptr);
variable_ptr->refcount=1;
break;
}
*variable_ptr_ptr = value;
value->refcount++;
break;
case IS_TMP_VAR:
ALLOC_ZVAL(*variable_ptr_ptr);
value->refcount=1;
**variable_ptr_ptr = *value;
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
(*variable_ptr_ptr)->is_ref=0;
}
The first if:
if the left variable (represented by the pointer variable_ptr) is a
reference, the value is assigned to the reference.
Otherwise (here we go, the variable is NOT a reference):
First, the refcount is decreased, because the variable gets a new value.
If then the refcount is zero, the allocated memory for variable_ptr is
reused.
If the refcount is not zero, we cannot do this, as we would overwrite all
other variables
(remember: internally, the variable is still stored as a refernce to the
value it has been assigned before)
In this case, it is checked if the value (that shall be assigned to the
variable) itself is a reference.
If this is the case, it gets copied to the memory space of the variable
pointer.
(NOTE: a TMP_VAR is a literal (i.e. a number, string, NULL or boolean
written DIRECTLY into the code, like $foo = 5;),
a CONST is a variable, i.e. sth like $foo = $bar;)
After that, the memory adress of our variable gets changed to the memory
adress of the value assigned, and the reference counter is increased :)
So we have evidence: definitely a reference, even if not explicitely
assigned as one :)
Well, now I am curious what you're gonna say about that ;)
Regards,
David