I have a function that gets users from a MySQL database, the results rows can be 1 or multiple rows.
What annoys me is that when i'm only looking to get 1 result from the db, it returns me a multi-dimentional array like this:
$result = array([0]=>array('foo'=>'bar'))
And makes me write nasty code like:
$e = $result[0]['foo'] // instead of $result['foo']
I'm pretty sure that many people came across this situation, i thought it would be cool if i can check if there is only one row returned and then append to $result an ungrouped version of it so i can use it when i'm looking for only 1 row. so it'd be like this:
$result = array(
[0] => array('foo'=>'bar'), // will keep the multi-dimentional version
'foo' => 'bar' // and append the ungrouped version of $result here
);
How to do that?
if ( count($result) === 1)
{
$result = $result[0];
}
Sounds to me like something's a little wonky in your API.
If you have a function that can return 1 to n results from a database, then it should be accessed through array accessors (such as $result[0]['foo']). Alternatively, you could store the result in a temp var, such as:
$o = $result[0];
print_r($o['foo']);
The problem with doing what you're asking is that you're munging your return data on a special case basis, which is not only confusing to those who may use your code, but it's very error-prone, potentially leaving a user wondering why they can't access the 0th element of $result.
Functions that return a single element should return a single element. Functions that return multiple elements should return multiple elements (and not have their data changed on special cases).
Related
I am trying to build an associative array to save the following information. A url, a word, and a frequency (# of occurrences of that word on that webpage).
I want to be able to access the information where I enter a string for the url and word and receive the frequency, like this:
$test["somewhere.com"]["biology"] => 5
$test["somewhere.com"]["auto"] => 10
$test["elsewhere.com"]["biology"] => 7
Right now I am pulling the information out of a db one row at a time and am trying the following:
$test["$url"] = array("$word" => "$freq");
After every iteration it gets over written. How do I change the syntax to avoid this situation? Is it possible to build the structure I want?
Thanks.
EDIT:
I was assigning values to array in a while loop. I made the mistake of initializing the array within the loop. I wasn't overwriting entries, I was
re-initializing the array unintentionally. That was my problem.
You are reassigning $test["$url"] as a new array each time. Use the full path:
$test[$url][$word] = $freq;
Also, no need for the quotes.
Instead of overwriting the first level contents, declare a new property for it. (without knowing how are you getting your urls, words and frequencies, the following is just an example)
$test = []
foreach($urls as $url => $words) {
$test[$url]=[];
foreach( $words as $word => $freq) {
$test[$url][$word] = $freq;
}
}
However, this looks awfully like trying to build an associative array that's already built.
Bear with me, I'm learning.
I often see snippets like the one below:
<?p
$imageArray = get_field('image_field');
$imageAlt = $imageArray['alt'];
$imageURL = $imageArray['url'];
?>
It is pedagogical and clear and organized. But is it necessary to get the entire array before querying the array for values? Can I not define the variable in just a single line? Something like the below (which doesn't work, neither the other variants I have tried):
$imageAlt = get_field('image_field', ['alt']);
$imageURL = get_field('image_field', ['url']);
Yes, you can.
As of PHP 5.4 it is possible to array dereference the result of a function or method call directly. Before it was only possible using a temporary variable. - Source
$imageAlt = get_field('image_field')['alt'];
https://eval.in/548036
The question you are asking can be answered by asking 2 questions:
Is it doable ?
Is it a good idea to do it that way ?
Is it doable ?
Yes! You do not have to store the array in a variable and re-use it later.
For instance, you could do:
$imageAlt = get_field('image_field')['alt'];
Note: This will work in PHP 5.4+ and is called: Array dereferencing.
But that is not the only consideration...
Is it a good idea to do it that way ?
No. It's not a good idea in many cases. The get_field() function, depending on your context, is probably doing a lot of work and, each time you call it, the same work is don multiple times.
Let's say you use the count() function. It will count the number of items in an array. To do that, it must iterate through all items to get the value.
If you use the count() function each time you need to validate number of items in an array, you are doing the task of counting each and every time. If you have 10 items in your array, you probably won't notice. But if you have thousands of items in your array, this may cause a delay problem to compute your code (a.k.a. it will be slow).
That is why you would want to do something like: $count = count($myArray); and use a variable instead of calling the function.
The same applies to your question.
While PHP 5.4+ allows you to directly dereference a function return value like this:
get_field('image_field')['alt']
...in this particular case I would not suggest you do so, since you're using two values from the resulting array. A function call has a certain overhead just in itself, and additionally you don't know what the function does behind the scenes before it returns a result. If you call the function twice, you may incur a ton of unnecessary work, where a single function call would have done just as well.
This is not to mention keeping your code DRY; if you need to change the particulars of the function call, you now need to change it twice...
PHP allows you to play around quite a bit:
function foo(){
return array('foo' => 1, 'bar' => 2);
}
Option 1
echo foo()['foo']; // 1
# Better do this if you plan to reuse the array value.
echo ($tmp = foo())['foo']; // 1
echo $tmp['bar']; // 2
It is not recommended to call a function that returns an array, to specifically fetch 1 key and on the next line doing the same thing.
So it is better to store the result of the function in a variable so you can use it afterwards.
Option 2
list($foo, $bar) = array_values(foo());
#foo is the first element of the array, and sets in $foo.
#bar is the second element, and will be set in $bar.
#This behavior is in PHP 7, previously it was ordered from right to left.
echo $foo, $bar; // 12
Option 3
extract(foo()); // Creates variable from the array keys.
echo $foo, $bar;
extract(get_field('image_field'));
echo $alt, $url;
Find more information on the list constructor and extract function.
The answer might be write two functions! However, maybe a little knowledge that I do not have will help avoid a heck of a lot of re-factoring or database usage.
I have a function with the very common syntax of:
while($row = $db->sql_fetchrow($result)) {
// do some stuff
}
Most of the time, the $row will be a mysql object with zero, one or more rows therein. Simple.
However, it would be very handy if I could also utilise a three dimensional PHP array (previously built to be a bunch of "rows" with three key & value pairs) without handling them differently.
The question I have is "What do I need to do to a 3D array to "convert" it to a mysql object that will work without change in the above example"?
There isn't a way to convert into a mysql object without writing to a tmp table and reading it back in. The following will deal with either sql statement or array turning up which then negates the need to convert as the question asked.
$all_rows = $notify->notification_sql(); // This either returns an SQL statement ready to run OR a set of rows in an array
if (!is_array($all_rows)) { // If it's not an array, run the SQL query and put it into an array of rows
$result = $db->sql_query($all_rows);
$all_rows = array();
while($row = mysql_fetch_array($result)) {
$all_rows[] = $row;
}
}
foreach...
The code below won't work because of this line $params=array($data);. It needs something other than $data. Or it needs something to happen with $data prior to this line.
If the line is written as $params=array("A", "B", "C", "D"); then it works great, but my array is in the $data variable, not written out like that. If there is a way to get the array converted to being written out like that, that would work too.
The end result should show every possible combination (not permutation) of the contents of the array. Like in the example above it shows ABC, BD, etc.
$data = mysql_query('SELECT weight FROM my_table WHERE session_id = "' . session_id() . '"');
$params=array($data);
$combinations=getCombinations($params);
function getCombinations($array)
{
$length=sizeof($array);
$combocount=pow(2,$length);
for ($i=1; $i<$combocount; $i++)
{
$binary = str_pad(decbin($i), $length, "0", STR_PAD_LEFT);
$combination='';
for($j=0;$j<$length;$j++)
{
if($binary[$j]=="1")
$combination.=$array[$j];
}
$combinationsarray[]=$combination;
echo $combination."<br>";
}
return $combinationsarray;
}
mysql_query() only returns a result resource ID. To retrieve data, you must use one of the "fetch" commands, for example
$params = array();
while ($row = mysql_fetch_assoc($data)) {
$params[] = $row['weight'];
}
Also, your query is possibly vulnerable to SQL injection. I wouldn't implicitly trust the value from session_id(). I'm not entirely sure of this but it may simply retrieve the value from the session cookie.
At the very least, sanitise the value with mysql_real_escape_string(). A more robust solution which would bring your code out of the dark ages would be to use PDO and parameter binding.
$data is not an array. Assuming mysql_query() did not return an error or an empty result (both of which you should check for, by the way--lookup documentation for mysql_error() and mysql_num_rows() perhaps, maybe some others), $data is a resource.
So you want $params=mysql_fetch_array($data) to make it an array. (That assumes that there is only one result. If it might return more than one row, you'll probably want to wrap it in a loop. If you are 100% certain that session_id is unique , then you can get away without the loop, I suppose. You can also get away without the loop if you only care about the first result in a multi-row result, although I'd throw in a LIMIT 1 in your query in that case to improve performance.)
There are lots of options (do you want a numerically indexed array, or one where they keys are the names of the columns, etc.) so read up at http://www.php.net/manual/en/function.mysql-fetch-array.php.
Ok there are alot of fundamental problems with your script. I personally recommend to first read this article and then about the actual function called mysql_fetch_array().
Simply put, what you are receiving from mysql is resource (corrent me if i'm wrong!) and you have to fetch array on that.
$params = mysql_fetch_array($data);
PS: This makes no sense: $params=array($data);
I have firePHP so i know exactly what the variables are, but I can't figure out why this code doesn't change it.
I receive from a mySQL call $query (which if returned produces [{"type":"2"}])
I have 4 potential types, and things can be multiple types (i.e. [{"type":"1"},{"type":"2"}])
Now I want to read this data and run various other functions based on the type it has, that is: if it's only type 2, call function TWO, if it's type 1 and 2 call function ONE and function TWO. I thought this would be easiest if i moved all the data into another array.
Here is the code I currently have:
$result = array('message'=>false, 'money'=>false, 'glasses'=>false, 'exclamation'=>false);
if (in_array('1',$query)) {$result['message'] = true;}
if (in_array('2',$query)) {$result['money'] = true;}
if (in_array('3',$query)) {$result['glasses']=true;}
if (in_array('4',$query)) {$result['exclamation']=true;}
echo json_encode($result);
This however does not update the $result array (as I can tell all of the values of $message are false in firePHP.... Thus I assume something is wrong with my if statements, but what?
I´m not sure about the value of $query, but if it is something like:
array [0 => '{"type":"2"}']
You would have to use:
in_array('{"type":"2"}',$query)
as that is the value of your variable.
Is it because the results returned in $query are arrays of arrays, and thus in_array is only searching at the top level and not sub-levels? It seems like what you want is to recursively search $query.