Hi PHP-Devs,
i don't know if it is a bug or a new feature of php5. The php manual
says, that using superglobals for variable variables isn't working, so
something like this shouldn't work:
<?php
$a = 'hello world';
echo ${$_GET['test']};
?>
Actually it does work. Is this intended now? Would be nice, but if it is
a simple bug and i can't rely on it to work in the future, i won't use
it. Hope it is a feature though. ;)
Regards, Michael
The idea is that the following doesn't work by design:
$a = "_GET";
var_dump($$a);
At 11:31 PM 1/28/2005 +0100, Michael Virnstein wrote:
Hi PHP-Devs,
i don't know if it is a bug or a new feature of php5. The php manual says,
that using superglobals for variable variables isn't working, so something
like this shouldn't work:<?php
$a = 'hello world';
echo ${$_GET['test']};
?>
Actually it does work. Is this intended now? Would be nice, but if it is a
simple bug and i can't rely on it to work in the future, i won't use it.
Hope it is a feature though. ;)Regards, Michael
but this does also work, atm. i'm using PHP 5.0.2 on Windows XP with
apache 1.3 and if i call my php page with
http://localhost/test.php?test=works it works.
//test.php
<?php
$a = '_GET';
echo ${$a}['test'];
var_dump($$a);
?>
the output is:
works
array(1) {
["test"]=>
string(5) "works"
}
Andi Gutmans wrote:
The idea is that the following doesn't work by design:
$a = "_GET";
var_dump($$a);At 11:31 PM 1/28/2005 +0100, Michael Virnstein wrote:
Hi PHP-Devs,
i don't know if it is a bug or a new feature of php5. The php manual
says, that using superglobals for variable variables isn't working, so
something like this shouldn't work:<?php
$a = 'hello world';
echo ${$_GET['test']};
?>
Actually it does work. Is this intended now? Would be nice, but if it
is a simple bug and i can't rely on it to work in the future, i won't
use it. Hope it is a feature though. ;)Regards, Michael
ok, sorry, now i have it. i read the german manual version first and
that says that you can't use what i said. The german is wrong and the
english version of the manual has it right. It says:
"Please note that variable variables cannot be used with PHP's
Superglobal arrays within functions or class methods."
i tested it and it is true, you can't used it inside functions, because
the variable would not reference to the superglobal variable this way.
<?php
function test() {
$a = '_GET';
var_dump($$a); // $$a has no reference to the superglobal $_GET
}
test();
?>
the output is
NULL
Anyway, thanks for your time. ;)
Regards, Michael
Michael Virnstein wrote:
but this does also work, atm. i'm using PHP 5.0.2 on Windows XP with
apache 1.3 and if i call my php page with
http://localhost/test.php?test=works it works.//test.php
<?php$a = '_GET';
echo ${$a}['test'];
var_dump($$a);
?>
the output is:
works
array(1) {
["test"]=>
string(5) "works"
}Andi Gutmans wrote:
The idea is that the following doesn't work by design:
$a = "_GET";
var_dump($$a);At 11:31 PM 1/28/2005 +0100, Michael Virnstein wrote:
Hi PHP-Devs,
i don't know if it is a bug or a new feature of php5. The php manual
says, that using superglobals for variable variables isn't working,
so something like this shouldn't work:<?php
$a = 'hello world';
echo ${$_GET['test']};
?>
Actually it does work. Is this intended now? Would be nice, but if it
is a simple bug and i can't rely on it to work in the future, i won't
use it. Hope it is a feature though. ;)Regards, Michael
but this does also work, atm. i'm using PHP 5.0.2 on Windows XP with
apache 1.3 and if i call my php page with
http://localhost/test.php?test=works it works.//test.php
<?php
$a = '_GET';
echo ${$a}['test'];
var_dump($$a);
?>
It works when you're already at the global scope, but try this:
<?php
function foo() {
var_dump($_GET);
$g = '_GET';
var_dump($$g);
}
foo();
?>
The first var_dump()
will work right because $_GET is a superglobal and ZE
picks it out of the global context correctly, the second var_dump()
will
yield a NULL
and an undefined index since it will try to access it from the
local symbol table and not find it.
Declaring a variable as superglobals is just a hint to the scripting engine
to retreive it from the global symbol table rather than the active symbol
table (Superglobals, by definition live in the global symbol table).
Your example worked because at the time the variable variable was resolved,
the global symbol table WAS the active symbol table.
-Sara
yep, figured it out already. Problem is the german version of the
manual. It is wrong and doesn't say anything about functions and
methods. It simply says you can't use superglobals for variable variable
and uses a illogical example ${$_GET}, whatever that should mean ;). The
english manual is right though and says you can't use it in functions
and methods.
Thanks anyway, Michael
Sara Golemon wrote:
but this does also work, atm. i'm using PHP 5.0.2 on Windows XP with
apache 1.3 and if i call my php page with
http://localhost/test.php?test=works it works.//test.php
<?php
$a = '_GET';
echo ${$a}['test'];
var_dump($$a);
?>It works when you're already at the global scope, but try this:
<?php
function foo() {
var_dump($_GET);
$g = '_GET';
var_dump($$g);
}foo();
?>The first
var_dump()
will work right because $_GET is a superglobal and ZE
picks it out of the global context correctly, the secondvar_dump()
will
yield aNULL
and an undefined index since it will try to access it from the
local symbol table and not find it.Declaring a variable as superglobals is just a hint to the scripting engine
to retreive it from the global symbol table rather than the active symbol
table (Superglobals, by definition live in the global symbol table).Your example worked because at the time the variable variable was resolved,
the global symbol table WAS the active symbol table.-Sara
one thing though. Will this behaviour change in future versions?
I think it is somehow odd and inconsistent to not be able to use them
with variable variables inside functions and methods. It's an
unnecessary restriction and will keep ppl using the old $HTTP_*_VARS. I
also see no reason for it to stay that way and i think it wasn't
intended by the developers in the first place but turned out to be that
way afterwards. So I hope it'll change, would make more sense.
Regards, Michael
Atm it isn't possible to use a construct like $var = ${'GET'}; inside a
function or method. Will this behaviour change in future versions of
PHP? I think it is somehow odd and inconsistent to not be able to use
the superglobals that way, while it is possible outside of functions and
methods and also with any other variable, e.g. the $HTTPVARS.
Imo it's an unnecessary restriction and will keep ppl using the old
$HTTP_VARS. I also see no reason for it to stay that way and i think
it wasn't intended by you, the developers, in the first place but turned
out to work that way afterwards.
So I really hope it'll change, would make much more sense. What do you
think?
Regards, Michael
P.S.: Sorry for the "double" post, but i thought this is worth an own
"topic".
On Mon, 31 Jan 2005 19:27:31 +0100, Michael Virnstein
michael.virnstein@brodos.de wrote:
Atm it isn't possible to use a construct like $var = ${'GET'}; inside a
function or method. Will this behaviour change in future versions of
PHP? I think it is somehow odd and inconsistent to not be able to use
the superglobals that way, while it is possible outside of functions and
methods and also with any other variable, e.g. the $HTTPVARS.
Imo it's an unnecessary restriction and will keep ppl using the old
$HTTP_VARS. I also see no reason for it to stay that way and i think
it wasn't intended by you, the developers, in the first place but turned
out to work that way afterwards.
So I really hope it'll change, would make much more sense. What do you
think?
Try
$_GET['foo'] = 'bar';
function x($val, $sg) {
return $GLOBALS[$sg][$val];
}
echo x('foo','_GET');
Regards,
Jason
http://blog.casey-sweat.us/
Atm it isn't possible to use a construct like $var = ${'GET'}; inside a
function or method. Will this behaviour change in future versions of
PHP? I think it is somehow odd and inconsistent to not be able to use
the superglobals that way, while it is possible outside of functions and
methods and also with any other variable, e.g. the $HTTPVARS.
Imo it's an unnecessary restriction and will keep ppl using the old
$HTTP_VARS. I also see no reason for it to stay that way and i think
it wasn't intended by you, the developers, in the first place but turned
out to work that way afterwards.
So I really hope it'll change, would make much more sense. What do you
think?
It comes down to how autoglobals are resolved.
When a script containg $_GET is parsed, ZE says "Oh, _GET is a registered
autoglobal, I'll flag that for fetching from the global symbol table".
Important factoid here: The target hashtable is resolved at compile time.
All other variable lookups (not entirely true, but run with me here) are
resolved at run-time roughly thus:
Check (hashtable) for (expression)
In the case of $foo these break down as:
Check (active_symbol_table) for ('foo' index)
In the case of $bar['foo'] they become:
Check (Check (active_symbole_table) for ('bar' index')) for ('foo' index)
So in order for ZE to resolve the autoglobals correctly during runtime it
has to ask two questions for every part of every variable resolution: "Are
we checking against the active symbol table? Is the index we're looking for
in the autoglobal registry?" If so, replace active_symbol_table with the
global symbol_table, otherwise do the lookup as normal.
Putting this extra bundle of steps completely negates the speed-benefit of
resolving autoglobals at compile time.
Given that, I certainly wouldn't hold my breath waiting for that
functionality to change.
-Sara
P.S. - This is why:
$a['b']['c']['d']['e']['f'][] = 1;
$a['b']['c']['d']['e']['f'][] = 2;
$a['b']['c']['d']['e']['f'][] = 3;
$a['b']['c']['d']['e']['f'][] = 4;
is slower than:
$b = &$a['b']['c']['d']['e']['f'];
$b[] = 1;
$b[] = 2;
$b[] = 3;
$b[] = 4;
Since in the first example the engine is doing 24 hash table lookups as
opposed to 11 in the second example.
And yes, $a['b']['c']['d']['e']['f'] = range(1,4); would be even faster....
it's called an example :p
So in order for ZE to resolve the autoglobals correctly during runtime it
has to ask two questions for every part of every variable resolution:
"Are
we checking against the active symbol table? Is the index we're looking
for
in the autoglobal registry?" If so, replace active_symbol_table with the
global symbol_table, otherwise do the lookup as normal.
I knew this statement felt wrong when I wrote it so I dove in and looked at
the code again....It's not actually necessary to test the what scope we're
in because of the way the parser is laid out... however it does still add an
extra hashtable lookup that shouldn't be necessary, so my original position
stands as is for now.
If someone would like to benchmark the following patch (Or point out any
fatal flaws in it) I'd be interrested in the results, but even if there's no
perceptible difference over a million itterations, I'd probably still
vote -1 on changing it.
-Sara
Index: Zend/zend_execute.c
RCS file: /repository/ZendEngine2/zend_execute.c,v
retrieving revision 1.692
diff -u -r1.692 zend_execute.c
--- Zend/zend_execute.c 22 Jan 2005 02:29:18 -0000 1.692
+++ Zend/zend_execute.c 31 Jan 2005 22:13:50 -0000
@@ -1001,6 +1001,10 @@
{
switch (opline->op2.u.EA.type) {
case ZEND_FETCH_LOCAL:
-
if (zend_hash_exists(CG(auto_globals),
variable->value.str.val, variable->value.str.len + 1)) {
-
/* Dynamically resolved auto global */
-
return &EG(symbol_table);
-
} return EG(active_symbol_table); break; case ZEND_FETCH_GLOBAL:
$_GET is solved at compile time, which is good, but this make other
variables bad at execution time?
how much does this patch slow execution down? it's one more hash lookup.
affect speed of $var or $$var? or both?
So in order for ZE to resolve the autoglobals correctly during runtime it
has to ask two questions for every part of every variable resolution:
"Are
we checking against the active symbol table? Is the index we're looking
for
in the autoglobal registry?" If so, replace active_symbol_table with the
global symbol_table, otherwise do the lookup as normal.I knew this statement felt wrong when I wrote it so I dove in and looked at
the code again....It's not actually necessary to test the what scope we're
in because of the way the parser is laid out... however it does still add an
extra hashtable lookup that shouldn't be necessary, so my original position
stands as is for now.If someone would like to benchmark the following patch (Or point out any
fatal flaws in it) I'd be interrested in the results, but even if there's no
perceptible difference over a million itterations, I'd probably still
vote -1 on changing it.-Sara
Index: Zend/zend_execute.c
RCS file: /repository/ZendEngine2/zend_execute.c,v
retrieving revision 1.692
diff -u -r1.692 zend_execute.c
--- Zend/zend_execute.c 22 Jan 2005 02:29:18 -0000 1.692
+++ Zend/zend_execute.c 31 Jan 2005 22:13:50 -0000
@@ -1001,6 +1001,10 @@
{
switch (opline->op2.u.EA.type) {
case ZEND_FETCH_LOCAL:
if (zend_hash_exists(CG(auto_globals),
variable->value.str.val, variable->value.str.len + 1)) {
/* Dynamically resolved auto global */
return &EG(symbol_table);
} return EG(active_symbol_table); break; case ZEND_FETCH_GLOBAL:
AFAICS, it should make every local-variable (non-global) lookup slower.
Since it needs to do a lookup in the globals table first.
Xuefer Tinys wrote:
$_GET is solved at compile time, which is good, but this make other
variables bad at execution time?how much does this patch slow execution down? it's one more hash lookup.
affect speed of $var or $$var? or both?So in order for ZE to resolve the autoglobals correctly during runtime it
has to ask two questions for every part of every variable resolution:"Are
we checking against the active symbol table? Is the index we're looking
for
in the autoglobal registry?" If so, replace active_symbol_table with the
global symbol_table, otherwise do the lookup as normal.I knew this statement felt wrong when I wrote it so I dove in and looked at
the code again....It's not actually necessary to test the what scope we're
in because of the way the parser is laid out... however it does still add an
extra hashtable lookup that shouldn't be necessary, so my original position
stands as is for now.If someone would like to benchmark the following patch (Or point out any
fatal flaws in it) I'd be interrested in the results, but even if there's no
perceptible difference over a million itterations, I'd probably still
vote -1 on changing it.-Sara
Index: Zend/zend_execute.c
RCS file: /repository/ZendEngine2/zend_execute.c,v
retrieving revision 1.692
diff -u -r1.692 zend_execute.c
--- Zend/zend_execute.c 22 Jan 2005 02:29:18 -0000 1.692
+++ Zend/zend_execute.c 31 Jan 2005 22:13:50 -0000
@@ -1001,6 +1001,10 @@
{
switch (opline->op2.u.EA.type) {
case ZEND_FETCH_LOCAL:
if (zend_hash_exists(CG(auto_globals),
variable->value.str.val, variable->value.str.len + 1)) {
/* Dynamically resolved auto global */
return &EG(symbol_table);
} return EG(active_symbol_table); break; case ZEND_FETCH_GLOBAL:
how much does this patch slow execution down? it's one more hash lookup.
affect speed of $var or $$var? or both?AFAICS, it should make every local-variable (non-global) lookup slower.
Since it needs to do a lookup in the globals table first.
Slows the global ones too, though that can be reduced (while slightly
worsening the non-global lookups) by not bothering to lookup the auto_global
table if we're in the global scope already...
-Sara
Sara Golemon wrote:
Index: Zend/zend_execute.c
RCS file: /repository/ZendEngine2/zend_execute.c,v
retrieving revision 1.692
diff -u -r1.692 zend_execute.c
--- Zend/zend_execute.c 22 Jan 2005 02:29:18 -0000 1.692
+++ Zend/zend_execute.c 31 Jan 2005 22:13:50 -0000
@@ -1001,6 +1001,10 @@
{
switch (opline->op2.u.EA.type) {
case ZEND_FETCH_LOCAL:
if (zend_hash_exists(CG(auto_globals),
variable->value.str.val, variable->value.str.len + 1)) {
/* Dynamically resolved auto global */
return &EG(symbol_table);
} return EG(active_symbol_table); break; case ZEND_FETCH_GLOBAL:
i must admit, that i don't know very much about the zend engine and the
php core in general, but if "opline->op2.u.EA.type" "knows" if the
variable is a local one, a global one or a static one, why hasn't it the
value of ZEND_FETCH_GLOBAL for superglobals in the first place?
Michael
i must admit, that i don't know very much about the zend engine and the
php core in general, but if "opline->op2.u.EA.type" "knows" if the
variable is a local one, a global one or a static one, why hasn't it the
value of ZEND_FETCH_GLOBAL for superglobals in the first place?
opline->op2.u.EA.type is set at compile time.
In the case of $_GET, the compiler knows that _GET is a superglobal so it
sets it to ZEND_FETCH_GLOBAL
In the case of $$g (where $g was previously set to '_GET') the compiler
doesn't know what $g is yet (since it's only really set at runtime), so it
has no reason to set it to ZEND_FETCH_GLOBAL.
Could it be intelligent enough to see that in:
$g = '_GET';
$$g is always going to be '_GET' and therefor $$g and $_GET are really the
same thing?
Perhaps.
But what about:
$g = '_';
$g .= 'G';
$g .= 'E';
$g .= 'T';
Or the enigmatic:
$g = '_TRG';
$g = str_rot13($g);
Building the run-time intelligence into a compiler would be.... well do I
really need to spell that one out?
-Sara
ok, i see. But why does it work with variables that are set as global,
e.g. the $HTTP_*_VARS:
<?php
function test() {
global $HTTP_GET_VARS;
$a = 'HTTP_GET_VARS';
var_dump($$a);
}
test();
?>
this works inside a function. is it because of the global keyword? If
so, why can't there be a "magic" "global $_GET, $_POST, $_SESSION ..."
set in every function, for every superglobal, instead of the way it is
handled now? The thing i don't get is, why the superglobals behave
differently than "normal" global variables at all. Ok, you have
explained the technical reasons, but that's not what i mean. For me as a
php user (developing in php), the only difference should be, that i
don't have to use the global keyword. Everything else seems like a bug
or design flaw to me. Sure i can work around the restriction somehow,
but this should not be the final solution.
Sorry to bother you further. ;)
Michael
Sara Golemon wrote:
i must admit, that i don't know very much about the zend engine and the
php core in general, but if "opline->op2.u.EA.type" "knows" if the
variable is a local one, a global one or a static one, why hasn't it the
value of ZEND_FETCH_GLOBAL for superglobals in the first place?opline->op2.u.EA.type is set at compile time.
In the case of $_GET, the compiler knows that _GET is a superglobal so it
sets it to ZEND_FETCH_GLOBAL
In the case of $$g (where $g was previously set to '_GET') the compiler
doesn't know what $g is yet (since it's only really set at runtime), so it
has no reason to set it to ZEND_FETCH_GLOBAL.Could it be intelligent enough to see that in:
$g = '_GET';
$$g is always going to be '_GET' and therefor $$g and $_GET are really the
same thing?
Perhaps.But what about:
$g = '_';
$g .= 'G';
$g .= 'E';
$g .= 'T';Or the enigmatic:
$g = '_TRG';
$g = str_rot13($g);Building the run-time intelligence into a compiler would be.... well do I
really need to spell that one out?-Sara
ok, i see. But why does it work with variables that are set as global,
e.g. the $HTTP_*_VARS:<?php
function test() {
global $HTTP_GET_VARS;
$a = 'HTTP_GET_VARS';
var_dump($$a);
}
test();
?>
global $foo;
is the equivalent of:
$foo = &$GLOBALS['foo'];
So when you access $$a, you're getting 'HTTP_GET_VARS' from the LOCAL symbol
table (where it exists as a reference of the global symtable version).
this works inside a function. is it because of the global keyword? If so,
why can't there be a "magic" "global $_GET, $_POST, $_SESSION ..." set in
every function, for every superglobal, instead of the way it is handled
now? The thing i don't get is, why the superglobals behave differently
than "normal" global variables at all.
In a word: efficiency.
There's an expression: "Fast, Clean, Cheap: Pick Two".
The current implementation is Fast and Cheap, but as this thread has
highlighted, it's not entirely clean.
Ok, you have explained the technical reasons, but that's not what i mean.
For me as a php user (developing in php), the only difference should be,
that i don't have to use the global keyword. Everything else seems like a
bug or design flaw to me.
You won't hear a lot of argument from me. I just care less that it is the
way it is.
-Sara
Sara Golemon wrote:
You won't hear a lot of argument from me. I just care less that it is the
way it is.-Sara
:p. Ok, probably there will be some redesign when PHP 6 is on it's way,
perhaps not. :) Anyway, thanks for your time. ;)
Michael