Jump to content

Fairly simple globals question


M4verick

Recommended Posts

I just want to know how to create a global variable from within a function.

 

The reason I want to do this is I'm making mysql queries that may or may not have data in a function, if the data does indeed exist, I want to declare variables at that point.

My queries are grouped logically by year/month, and as a result I'm going to be appending data to existing variables if they exist so it makes more sense to just append it to what would be the global variable anyways instead of just passing large strings out of the function to just be appended anyways -- plus it prevents me from creating a bunch of pointless variables.

 

I intend additionally take the variables created inside the function and then store them in an encompassing global array (pre-defined outside of function) and at the end of the script do a foreach through it so I can iterate through the variables to grab my data knowing that there won't be pointless crap in there.

 

I'm trying to create global variables by using variable variables ($$whichever). The code giving me issues inside the function is just like this:

function SeekAndAppend ($vars, $being, $passed) {
   global $$whatever;         // Trying to define it here
   global $array;             // Calling predefined $array
   $array[] = "$$whatever";   // Passing just created global to the array for iteration later
}

 

When I iterate through the array the expected name of what would be the global variable name is there, but the global variable itself does not exist -- just at the function level.

 

If someone has a recommendation on a better way to do it, I'll listen, but please don't turn it into a lecture.  ::)

 

EDIT: Grammar & Clarity

Link to comment
Share on other sites

A better way to do this would be to not use the global keyword, and keep everything in it's own scope. You can pass by reference to avoid redundancy, but again, it's easier to debug if you stick to altering values within their own scope.

 

I'll end it there, to avoid posting a 'lecture'

 

PS: Rolling eyes and telling people how you expect to be helped is not generally a good way to get volunteers to help you.

 

http://www.php.net/manual/en/reserved.variables.globals.php

Link to comment
Share on other sites

A better way to do this would be to not use the global keyword, and keep everything in it's own scope. You can pass by reference to avoid redundancy, but again, it's easier to debug if you stick to altering values within their own scope.

 

I'll end it there, to avoid posting a 'lecture'

 

PS: Rolling eyes and telling people how you expect to be helped is not generally a good way to get volunteers to help you.

 

http://www.php.net/manual/en/reserved.variables.globals.php

 

Sorry, the eyes were not intended to sound condescending or create hostility.

I had read that document but it I could have sworn somewhere that it stated that you can't use that with variable variables.

Thanks for the input and I'll change the smiley because if you made that assumption, chances are others will too.

EDIT: Nm, can't change the post after something else is posted it appears.

 

@Psycho -- I'll read up on classes, I'm not familiar with them. Thanks for input.

Link to comment
Share on other sites

Using classes won't save you from having to pass global-scope variables.

 

You're just putting them into a class now, instead of a function.

 

<?php

$values = array('one','two','three');

$more_data = 'potato';

$even_more_data = 'patato';

// With functions

$values = put_into_array($more_data, $values);
$values = put_into_array($even_more_data, $values);

print_r( $values );
// Array ( [0] => one [1] => two [2] => three [3] => potato [4] => patato )

function put_into_array( $data, $array ) {
$array[] = $data;
return $array;
}

// With classes

$values = array('one','two','three');
$object = new ourArray($values);

$object->put_in($more_data);
$object->put_in($even_more_data);

print_r( $object->get_array() );
// Array ( [0] => one [1] => two [2] => three [3] => potato [4] => patato )

class ourArray {
protected $vals;
public function __construct( $array ) {
	$this->vals = $array;
}
public function put_in( $data ) {
	$this->vals[] = $data;
	return TRUE;
}
public function get_array() {
	return $this->vals;
}
}

?>

 

Classes create their own scope, but they still won't interact with the global scope unless you use $GLOBALS or the global keyword. You're still passing data in to it.

Link to comment
Share on other sites

Classes create their own scope, but they still won't interact with the global scope unless you use $GLOBALS or the global keyword. You're still passing data in to it.

 

From what I understood he was going to have several functions that would be acting upon these variables. I don't know the nature of these functions, but if they would logically encompass a class then the code could instantiate the class and the variable(s) he is wanting to work with. He could then call the various functions (methods) of the class and they could reference the variables within those methods using $this->varName instead of having to pass them around or using the GLOBAL keyword. Then in the procedural code he can execute the different methods as needed and reference the current values at any time using $objName->varName;

 

Without knowing how all the pieces fit together or not it's impossible to say if this is the right solution, but it is a possible solution.

Link to comment
Share on other sites

I understand, but it seems his goal is to avoid passing a bunch of data into functions.

 

I was simply saying whether you use a function, or class, you're going to have to pass data from the global scope.

Link to comment
Share on other sites

Ok, I'll try to clear it up a bit and hopefully there will be a consensus to a degree. (I'm just now getting time to dive back into the project, so I haven't tried anything else yet.)

 

Let's say I'm trying to query for objects A, B, and C for two months of whatever year. I had been trying to take that info and use it as the basis to store info of that category. Here's some pseudo code to try and give you the general idea.

 

// Main
$array = array();

// Algorithm determines dates to grab
query($day, $1, $vars);
// ...
query($day, $31, $vars);

foreach($array as &$item){
    // Now I can return data nice and grouped logically by year.month
}

function query ($vars, $being, $passed){

    // Pretend there's a bunch of stuff determining properties and data to query that would be here but isn't because it's unrelated to the question

    $data = mysql_query($statementA);
    if ($data){
        global ${$A.$year.$month};

        // This if statement checks to see if our variable has data in it, if not, then it must be new and should be added to the array for later iteration
        if (is_null(${$A.$year.$month})){
            global $array;
            $array[] = ${$A.$year.$month};
        }

        ${$A.$year.$month} .= $data;
    }

    $data = mysql_query($statementB);
    if ($data){
        global ${$B.$year.$month};
        if (is_null(${$B.$year.$month})){
            global $array;
            $array[] = ${$B.$year.$month};
        }
        ${$B.$year.$month} .= $data;
    }

    $data = mysql_query($statementC);
    if ($data){
        global ${$C.$year.$month};
        if (is_null(${$C.$year.$month})){
            global $array;
            $array[] = ${$C.$year.$month};
        }
        ${$C.$year.$month} .= $data;
    }
}

 

However, for each month, I might have to query for every single day, so ideally I could just append the data to those global variables I would have created if data had been there. That way it's easy for me to iterate through them in the array when I go to grab the data in the variables and just spew it out. Hopefully this helps.

Link to comment
Share on other sites

I think you are making this significantly harder than it needs to be and it will not scale. It looks like you are running multiple queries to get the data? Why? Just run ONE query for the entire period you need. Then when you process the records you can manipulate the output by day/month or whatever you need.

Link to comment
Share on other sites

The pseudo code is really simplified. It's not like I'm querying one table, there could be literally hundreds, it'd be really difficult to write one all encompassing query.

It actually scales fairly well. Would take me about 2-3 minutes to add in a new category altogether if I needed a new topic queried.

 

However, the only thing holding me back is just the output. If I have to just pre-define a bunch of variables before calling the function then I guess I'll do what I have to do, it just seems so inelegant. I really appreciate the input either way.

Link to comment
Share on other sites

You have to be careful with your terminology as well. In PHP, the word 'object' means something very specific. In PHP, you can't query a database for an object - you query a database for data.

 

You need to combine your logic as well. If you're querying for data in a two month range, why would you later need to query the individual days? You've already got the entire dataset for the months, which should contain data for 'every single day' in that range.

 

The code you've posted isn't a great way to do what you want. Here's how I'd do it. This code is for example only, and not production.

 

<?php

$data = array();
$columns = array( 'colA','colB','colC' );
// Select A,B,C from April or May, 2012
$query = 'SELECT '.implode(',',$columns).', YEAR(date) as date_year, MONTH(date) as date_month, DAY(date) as date_day
FROM myTable
WHERE (MONTH(date) = 4 OR MONTH(date) = 5) AND YEAR(date) = 2012';
$result = mysql_query($query);
if( $result )
while( $row = mysql_fetch_assoc($result) )
	foreach( $columns as $column )
		if( !empty($row[$column]) )
			$data[$column][$row['date_year']][$row['date_month']][$row['date_day'] = $row[$column];

print_r($data);

?>

 

The pseudo code is really simplified. It's not like I'm querying one table, there could be literally hundreds, it'd be really difficult to write one all encompassing query.

It actually scales fairly well. Would take me about 2-3 minutes to add in a new category altogether if I needed a new topic queried.

 

However, the only thing holding me back is just the output. If I have to just pre-define a bunch of variables before calling the function then I guess I'll do what I have to do, it just seems so inelegant. I really appreciate the input either way.

 

Hundreds of tables? I think you've got your database designed inefficiently as well.

 

With a relational database, there's only extreme cases where you can't grab related data in a single query, even across multiple tables.

 

Though you may not agree, by our standards your script does not scale well. Ideally, adding a new category should be simply typing in it's name, and columns you need data from. Also, you should be able to select 1 or 100 categories with similar query counts and no extra overhead outside of the difference in data selected.

Link to comment
Share on other sites

Sorry about terminology. The pseudo code was trying to give an example. I'm not actually going to be querying day by day where it can be avoided -- it will shoot for the whole month where applicable.

 

The database isn't fun, but probably as good as it gets because all the information in it is unique and doesn't actually relate to each other unfortunately, which is why there are so many different tables. But it's kind of the nature of the beast. Any record in one table will not have anything in common with a record in another table other than potentially a date range -- which is by coincidence even then.

 

It's essentially doing a 'select * from table' based on date and other parameters, and it does have to be a 'select *' unfortunately. But that's starting to get a bit off topic...

 

I like your example, but I don't think it will work in my situation. I know you guys are doing your best to help me out with limited info, I really do appreciate it.

Link to comment
Share on other sites

You should explain what you're doing in more detail. What kind of information are you dealing with? Why do you have to SELECT *?

 

How do you expect to process data when you don't know what columns you're selecting?

 

I promise you there are ways to do this more efficiently than you're trying, but it's probably going to mean a huge restructuring of your code and database.

Link to comment
Share on other sites

Think like SNMP Traps. I have a network source that hands me data which is collectively unique every single time. The only information that will be the same on every transaction is the relay it came from -- of which, I don't care about that, the rest of the information I do care about. There'd be basically a source tied to each transaction, which is the only thing that transactions could have in common otherwise. Each transaction is independent of any other transaction.

 

The data that comes in may be structured in a variety of potential ways -- we are able to decipher the kind of incoming data based on this structure, of which, gets input into a table for that type of structure.

 

So when I need a date range for a source, I need to find that date range, for that source, based on that structure, and all other information that structure can provide so that I know what is happening.

Link to comment
Share on other sites

I have a hard time understanding what it is your trying to do.  It doesn't make sense to me that you'd be querying this data and trying to group it if there is no relation between the data at all.  Near as I can tell though you're basically executing a bunch of queries, and each query has at least a month, year, and source field plus a bunch of other fields that depend on the source.  Is that about right?  Then you want to create an array structure that will group everything by source, year and month?

 

You could do this with a class and have a class-level array to store the data, or you can use your functions and just have a pass-by-reference array that collects the data into keys.  Something like:

 

// Main

//Collects all the information in a multi-level structure.
// - First level being source
// - Second level being Year
// - Third level being month
// - Fourth level being all the data
$finalData = array();

// Algorithm determines dates to grab
query($day, $1, $vars, $finalData);
// ...
query($day, $31, $vars, $finalData);

foreach($finalData as $source){
foreach ($source as $year){
	foreach ($year as $month){
		foreach ($month as $dataRow){
			foreach ($dataRow as $fieldName=>$fieldValue){
			}
		}
	}
}
}

function query ($vars, $being, $passed, &$dataArray){

    // Pretend there's a bunch of stuff determining properties and data to query that would be here but isn't because it's unrelated to the question

    $data = mysql_query($statementA);
    if ($data){
while ($row=mysql_fetch_assoc($data)){
	$src = $row['source'];
	$year = $row['year'];
	$month = $row['month'];
	if (!isset($dataArray[$src][$year][$month])){
		$dataArray[$src][$year][$month] = array();
	}

	$dataArray[$src][$year][$month][] = $row;
}
    }

    //Your other queries.
}

 

After all your functions run then your $finalData array should contain a nicely group set of your data, do with it what you will.  You could alter the structure if some other grouping would be easier to use or make more sense.

 

Link to comment
Share on other sites

Yeah pretty much. There's a source and a date. For whatever date range, I need all available info for the given source in whatever structures it may be apart of. You're the second person to say a class, I've been slammed and haven't had time to try it out yet. Appreciate input again guys, thanks everyone.

Link to comment
Share on other sites

Double posting only because I can't modify my last post and I figured out the original problem.

 

Using the original pseudo code, all I had to do was fix a syntax error on the global array deal.

 

function SeekAndAppend ($vars, $being, $passed) {
   global $$whatever;         // Trying to define it here
   global $array;             // Calling predefined $array
   $array[] = $whatever;   // This used to be - $array[] = "$$whatever";
}

foreach($array as $item){
    echo $$item;
}

 

I appreciate your input regardless guys and if I can find a method to redo it to make it more efficient, I absolutely will jump on it. But like I said, unfortunately it's kind of just the nature of the beast for this situation and it makes it less than ideal. Thanks again everyone.

Link to comment
Share on other sites

Pretty much. I can't say the actual purpose of what I'm working on, but SNMP trapping is the closest anology.

 

Each structure might contain a source, timestamp, and then a bunch of variables detailing what happened. Because they are situational you need all the info to put together what happened and if there's a problem, you'll want to know all the info so you know how to go about resolving it.

Link to comment
Share on other sites

Use a structure like this

 

sources - stores the names of even sources - id,name

events - stores a record for each trap notification - id,source_id,date

events_data - stores each variable related to an event - id,event_id,name,data

 

Here's some code I've written to interact with the database above, populated with a bit of sample data.

<?php

$db = new MySQLi('localhost','root','','db');

// INSERTING DATA
$incomingData = array(
'var1' => 'some data',
'var2' => 'more data',
'everybody' => 'dance now'
);
$dataSource = 'sourceC';

$db->autocommit(FALSE);
$q = 'INSERT INTO events ( date, source_id )
VALUES ( NOW(), (SELECT id FROM sources WHERE name="'.$db->escape_string($dataSource).'") )';
if( $db->query($q) ) {
$qData = array();
foreach( $incomingData as $name => $data )
	$qData[] = '(LAST_INSERT_ID(), "'.$db->escape_string($name).'", "'.$db->escape_string($data).'")';
$q = 'INSERT INTO events_data ( event_id, name, data ) VALUES '.implode(',',$qData);
if( $db->query($q) ) {
	echo 'Successful insert!';
	$db->commit();
} else {
	echo 'Some error occured, fix your damn query.';
	$db->rollback();
}
} else {
echo 'Tried to insert to a non-existant source, or some other error occured. Should check errno.';
}
// Put back to default
$db->autocommit(TRUE);

// SELECTING DATA
$months = array(4,5);
$years = array(2012);

$q = 'SELECT s.name source_name, e.id, e_d.name, e_d.data
FROM events_data e_d
	LEFT JOIN events e
		ON e.id = e_d.event_id
	LEFT JOIN sources s
		ON s.id = e.source_id
WHERE (MONTH(e.date)='.implode(' OR MONTH(e.date)=',$months).')
	AND (YEAR(e.date)='.implode(' OR YEAR(e.date)=',$years).')
ORDER BY e.id';
if( ($r = $db->query($q)) != FALSE ) {
$current = FALSE;
while( $row = $r->fetch_assoc() ) {
	if( $current != $row['id'] ) {
		echo '<h3>New event ('.$row['id'].') came from '.$row['source_name'].'</h3>';
		echo 'Details:<br>';
		$current = $row['id'];
	}
	echo $row['name'].' : '.$row['data'].'<br>';
}
} else {
echo 'Fix your select query, it\'s broken';
}

?>

 

It will allow you to select events from a specific source, date range, that contain certain variables, or certain data.

 

Hope this helps :D

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.