I am trying to define dynamically variables. I am using a function for this, but I don't know how to define the new var as global (because it never created before the function).
is that possible ?
Thanks.
edit
ok, this is what I've built. is it that dangerous ?
function extract_values($row) {
foreach ($row as $key => $value){
global $$key;
$$key = $value;
}
}
and then I'm trying to make my life easier like that:
$result = mysql_query("SELECT first_name, last_name, address FROM users ORDER BY id ASC");
while ($row = mysql_fetch_array($result)){
extract_values($row);
#[do some stuff with the variables.]#
}
I am doing it to save time. instead of creating for each column it's own variable like
$first_name = $row['first_name'];
This function does that for me.
I don't see why in this case it might be dangerous..
or as usuall, i am missing something..
Try this:
function doSomething() {
global $x;
$x = 5;
}
If you prefer to save a couple of bytes, you can use the $_GLOBALS array for this:
$_GLOBALS['x'] = 5;
Regarding your edit: It makes your code less understandable.
Actually, there already exists a function that is doing this: extract().
while (($row = mysql_fetch_assoc($result))){
extract($row);
// ...
}
extract() is even better, because it lets you specify what should happen if the variable already exists and/or lets you specify a prefix (so you don't overwrite already existing variables with that name). E.g. you could do:
extract($row, EXTR_PREFIX_ALL, 'db');
which would result in $db_first_name etc.
Surly, extract() is also doing some internal work here, but using built-in functions is always better than creating your own.
Another possibility would be to use list():
while (($row = mysql_fetch_row($result))){
list($first_name, $last_name, $address) = $row;
// ...
}
You can do it in two ways:
Make the variable global using the global keyword:
function fun1() {
global $foo;
$foo = 1;
}
Alternatively you can also create an new element in the $GLOBALS array:
function fun2() {
$GLOBALS['bar'] = 1;
}
Working code
Remember that these are considered bad practice, a function should have local variables invisible outside and should get inputs through the arguments passed. You should avoid getting arguments though global variables and must completely avoid crating global variables.
Related
I'm pretty new to php and I've read many times "avoid global variables" but I've not understood whether I have to follow this advice everytime or not.
I need some values (they are stored into two variables) into a function and I could put both variables as parameters:
$GVar1 = array(...); //This is a multidimensional array (over 80.000 chars in declaration)
$GVar2 = array(...);
$Result = DoMyStuff('BasicValue', $GVar1, $GVar2);
function DoMyStuff ($BasicParameter, $GV1, GV2){
//Do stuff
}
or declare variables as global into the function:
$GVar1 = array(...);
$GVar2 = array(...);
$Result = DoMyStuff('BasicValue');
function DoMyStuff ($BasicParameter){
global $GVar1;
global $GVar2;
//Do stuff
}
I would like to understand if the first way is really better .. and why?
I have a series of variables in php:
move1A = $row['column'];
move2A = $row['column'];
move3A = $row['column'];
etc.
I want to create a variable that will represent these variables and check if it is NULL. I have spent quite a bit of time looking, and although I believe that variable variables may be the key to my problem. So far I have tried:
$current_move_check = 'move'.$moveCounter.'A';
and
$current_move_check = '$move'.$moveCounter.'A';
Neither seem to work. Any suggestions for making something like this work? Thanks!
UPDATE:
So I'm trying to loop the moveXA variables based on user input and I need to run different script whether it is null or set.
I thought that:
elseif (!$$current_move_check) {
and
elseif ($$current_move_check) {
would work but they seem to not be outputting as expected.
Considering your update, I'd really suggest you to use an array, rather than the variable variables trick. Your code would makes more sense and be easier to maintain :
$count = 0;
$moveA[++$count] = $row['column'];
$moveA[++$count] = $row[...];
$moveA[++$count] = $row[...];
...
foreach ($moveA as $key => $value) {
if ($value) { // = $$current_move_check
} else { // = !$$current_move_check
}
}
As #MatsLindh pointed out in its comment : "Variable variables are never a good idea. Unless you know when it makes sense to break that rule, don't."
$current_move_check = 'move'.$moveCounter.'A';
echo $$current_move_check;
now you can check this as well like
if($$current_move_check!=NULL)
{
// do your code
}
When comparing the following scenarios, which one would be the fastest? Sample examplary code below.
Basically, what I'm trying to find out is what's the best alternative to using global vars.
The global vars that I store would be the same for all users... they are application level values which are the same for all users, application_name for example, or application_home_page_url...
I will have a ton of functions using these app level values and I do not want to pass them by argument, though I think that would be the fastest way.. My options seem to be working with either db look ups, or using session vars or globals..
Of course, you may take it to the next level by throwing the assoc. arrays into the equation to make it faster/?slower.
The other factor that we have to keep in mind is that we are talking about lots of users here.
So, what's the best way to toss around/work with these app level variables within individual functions?
//for global based approach
$my_global_var1 = "abc";
$my_global_var2 = "xyz";
//for global + array based approach
$my_globals['var1'] = "abc";
$my_globals['var2'] = "xyz";
//for session based approach
$_SESSION['my_global_var1'] = "abc"
$_SESSION['my_global_var2'] = "xyz";
//for session + array based approach
$_SESSION['my_globals']['var1'] = "abc";
$_SESSION['my_globals']['var2'] = "xyz";
//for db based approach
$varname = 'var1';
//or some other way, you may think of
//??
function func1()
{
global $my_global_var1;
global $my_global_var2;
//....
my_var1 = $my_global_var1;
}
function func2()
{
$my_var1 = $my_globals['var1'];
}
function func3()
{
$my_var1 = $_SESSION['my_global_var1'];
}
function func4()
{
$my_var1 = $_SESSION['my_globals']['var1'];
}
$my_var1 = func5($varname)
function func5($varname)
{
return lookup($varname);
}
I would suggest using a Registry class for this.
I'm sure there is more than one way to make such a class, but i prefer using a single static class:
class Registry {
private static $values = array();
public static function set($key, $value) {
self::$values[$key] = $value;
}
public static function get($key) {
return self::$values[$key];
}
}
Then you would just include the registry at the top of your application and interface it during with Registry::set('abc', 'xyz'); and Registry::get('abc');
A few links on this technique:
http://www.devshed.com/c/a/PHP/Registry-Design-Pattern/
http://www.phpro.org/tutorials/Model-View-Controller-MVC.html#5
The idea behind global variables and session variables is different. Global variables are for using the same variable in a single script, regardless of scope. Session is to store variables for one user across pages. If I understand what you're trying to do correctly, it's probably better to use session variables.
Regarding the speed, try to measure your script's execution time with microtime(). You can use this (note: input not sanitized!):
<?php
$start = microtime(true);
if ($_GET['include']) { #include $_GET['include']; }
$end = microtime(true);
echo '<hr />';
echo 'The script executed in: '.(($end - $start)*1000).' milliseconds.';
?>
EDIT:
The comment to your post above me just made me understand better what you're trying to do. Indeed in case these variables are supposed to stay constant, use constants.
You should pass variables to functions if possible.
Example where Global variables are used:
<?PHP
$Variable = '1234567';
function funcName()
{
global $Variable;
echo $Variable;
}
?>
or you could just do
<?PHP
$Variable = '1234567';
funcName($Variable);
function funcName($varPassed)
{
echo $varPassed;
}
?>
SESSION variables are used to store a user-specific setting or variable across multiple page loads, or pages. They are used to store session information (username,password, last page), but you have complete control of it. Also SESSION variables are stored in temp files. If the stuff your storing are for individual users, then use SESSION...MySQL will clog up if not designed right with proper indexes and such.
I have the following segment of code that someone else has written, and that I'm trying to fix:
function calc() {
require_once("db.php");
connect();
$a = split("#", $_SESSION['freight']);
$loc = $a[0];
$r = mysql_query("SELECT `price`, `gst` FROM `freight` WHERE `location`='$loc'");
$arr = mysql_fetch_array($r);
$_SESSION['freight'] = $loc."#".$arr['price'];
return $arr['price'];
}
function ajaxFunction () {
$_SESSION['freight'] = $_GET['loc'];
$freight = calc();
echo number_format($freight, 2);
return;
}
It ain't pretty, I am just trying to fix it.
Now I have noticed the bug seems to stem from the fact $freight = calc(). After that line, $freight will equal say $10 (the $arr['price'] value). BUT the $_SESSION['freight'] will also equal $10, and just $10, as if it was the same variable as $freight. What ever I set $freight to, the $_SESSION['freight'] also becomes.
If I change $freight in the ajax function to $freight2 it doesn't alter the session variable. Is this something major that I don't know about PHP? That variable names share the same namespace as session variables?
The question overall is:
Does changing $a alter $_SESSION['a'] in anyway? Because it really seems like it does.
It looks like your register globals is set to on in your php.ini file. You need to turn that off. If it's on, your $_SESSION, $_GET, $_POST elements can be referred to as the variable names.
e.g. $_SESSION['item'] is the same as $item
More info here: http://us2.php.net/manual/en/ini.core.php#ini.register-globals
Also, register globals is now deprecated, which also means that if this is indeed the issue, you were using an older version of PHP, and may want to consider upgrading.
As far as I can tell...
your $_SESSION variable should not be a session variable at all as it always equals $_SESSION['freight'] = $loc."#".$arr['price'];
I actually do not understand the use of the session so this is whow i would have approach it
function calc($loc)
{
require_once("db.php");
connect();
$r = mysql_query("SELECT `price`, `gst` FROM `freight` WHERE `location`='$loc'");
$arr = mysql_fetch_array($r);
$_SESSION['freight'] = $loc."#".$arr['price'];
return $arr['price'];
}
function ajaxFunction ()
{
$a = split("#", $_GET['loc']);
$freight = calc($a[0]);
echo number_format($freight, 2);
return;
}
You only need the location so that you can run your queries. So just set the session once with the new data from the database.
Hope that helps
I always use different notation for session variables. For example $_SESSION['_uid'] versus a regular $uid variable.
Anyone has an idea if this is at all possible with PHP?
function foo($var) {
// the code here should output the value of the variable
// and the name the variable has when calling this function
}
$hello = "World";
foo($hello);
Would give me this output
varName = $hello
varValue = World
EDIT
Since most people here 'accuse' me of bad practices and global variables stuff i'm going to elaborate a little further on why we are looking for this behaviour.
the reason we are looking at this kind of behaviour is that we want to make assigning variables to our Views easier.
Most of the time we are doing this to assign variables to our view
$this->view->assign('products', $products);
$this->view->assign('members', $members);
While it would be easier and more readable to just be able to do the following and let the view be responsible to determining the variable name the assigned data gets in our views.
$this->view->assign($products);
$this->view->assign($members);
Short answer: impossible.
Long answer: you could dig through apd, bytekit, runkit, the Reflection API and debug_backtrace to see if any obscure combination would allow you to achieve this behavior.
However, the easiest way is to simply pass the variable name along with the actual variable, like you already do. It's short, it's easy to grasp, it's flexible when you need the variable to have a different name and it is way faster than any possible code that might be able to achieve the other desired behavior.
Keep it simple
removed irrelevant parts after OP edited the question
Regardless of my doubt that this is even possible, I think that forcing a programmer on how to name his variables is generally a bad idea. You will have to answer questions like
Why can't I name my variable $arrProducts instead of $products ?
You would also get into serious trouble if you want to put the return value of a function into the view. Imagine the following code in which (for whatever reason) the category needs to be lowercase:
$this->view->assign(strtolower($category));
This would not work with what you're planning.
My answer therefore: Stick to the 'verbose' way you're working, it is a lot easier to read and maintain.
If you can't live with that, you could still add a magic function to the view:
public function __set($name, $value) {
$this->assign($name, $value);
}
Then you can write
$this->view->product = $product;
I don't think there is any language where this is possible. That's simply not how variables work. There is a difference between a variable and the value it holds. Inside the function foo, you have the value, but the variable that held the value is not available. Instead, you have a new variable $var to hold that value.
Look at it like this: a variable is like a bucket with a name on it. The content (value) of the variable is what's inside the bucket. When you call a function, it comes with its own buckets (parameter names), and you pour the content of your bucket into those (well, the metaphor breaks down here because the value is copied and still available outside). Inside the function, there is no way to know about the bucket that used to hold the content.
What you're asking isn't possible. Even if it was, it would likely be considered bad practice as its the sort of thing that could easily get exploited.
If you're determined to achieve something like this, the closest you can get would be to pass the variable name as a string and reference it in the function from the $GLOBALS array.
eg
function this_aint_a_good_idea_really($var) {
print "Variable name: {$var}\n";
print "Variable contents: {$GLOBALS[$var]}\n";
}
$hello="World";
this_aint_a_good_idea_really('hello');
But as I say, that isn't really a good idea, nor is it very useful. (Frankly, almost any time you resort to using global variables, you're probably doing something wrong)
Its not impossible, you can find where a function was invoked from debug_backtrace() then tokenize a copy of the running script to extract the parameter expressions (what if the calling line is foo("hello $user, " . $indirect($user,5))?),
however whatever reason you have for trying to achieve this - its the wrong reason.
C.
Okay, time for some ugly hacks, but this is what I've got so far, I'll try to work on it a little later
<?php
class foo
{
//Public so we can test it later
public $bar;
function foo()
{
//Init the array
$this->bar = array();
}
function assign($__baz)
{
//Try to figure out the context
$context = debug_backtrace();
//assign the local array with the name and the value
//Alternately you can initialize the variable localy
//using $$__baz = $context[1]['object']->$__baz;
$this->bar[$__baz] = $context[1]['object']->$__baz;
}
}
//We need to have a calling context of a class in order for this to work
class a
{
function a()
{
}
function foobar()
{
$s = "testing";
$w = new foo();
//Reassign local variables to the class
foreach(get_defined_vars() as $name => $val)
{
$this->$name = $val;
}
//Assign the variable
$w->assign('s');
//test it
echo $w->bar['s'];
}
}
//Testrun
$a = new a();
$a->foobar();
impossible - the max. ammount of information you can get is what you see when dumping
debug_backtrace();
Maybe what you want to do is the other way around, a hackish solution like this works fine:
<?php
function assign($val)
{
global $$val;
echo $$val;
}
$hello = "Some value";
assign('hello');
Ouputs: Some value
What you wish to do, PHP does not intend for. There is no conventional way to accomplish this. In fact, only quite extravagant solutions are available. One that remains as close to PHP as I can think of is creating a new class.
You could call it NamedVariable, or something, and as its constructor it takes the variable name and the value. You'd initiate it as $products = new NamedVariable('products', $productData); then use it as $this->view->assign($products);. Of course, your declaration line is now quite long, you're involving yet another - and quite obscure - class into your code base, and now the assign method has to know about NamedVariable to extract both the variable name and value.
As most other members have answered, you are better off suffering through this slight lack of syntactic sugar. Mind you, another approach would be to create a script that recognizes instances of assign()'s and rewrites the source code. This would now involve some extra step before you ran your code, though, and for PHP that's silly. You might even configure your IDE to automatically populate the assign()'s. Whatever you choose, PHP natively intends no solution.
This solution uses the GLOBALS variable. To solve scope issues, the variable is passed by reference, and the value modified to be unique.
function get_var_name(&$var, $scope=FALSE) {
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = 'unique'.rand().'value';
$vname = FALSE;
foreach ($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
$testvar = "name";
echo get_var_name($testvar); // "testvar"
function testfunction() {
$var_in_function = "variable value";
return get_var_name($var_in_function, get_defined_vars());
}
echo testfunction(); // "var_in_function"
class testclass {
public $testproperty;
public function __constructor() {
$this->testproperty = "property value";
}
}
$testobj = new testclass();
echo get_var_name($testobj->testproperty, $testobj); // "testproperty"